From 69496d0e45f47c5462d8143401df48ef4714206e Mon Sep 17 00:00:00 2001 From: Terry Mancey Date: Thu, 1 Jul 2021 17:26:35 -0500 Subject: [PATCH] Fixes estimated pending rewards does not reset to expected value when you have uncashed in tokens - follow up to #16678 --- .../data/test/confirmations_issue_16744.json | 182 +++++++++++++ .../confirmations_with_unblinded_tokens.json | 8 +- .../account/ad_rewards/ad_rewards_test.cc | 249 +++++++++++++++++- .../confirmations/confirmations_state.cc | 55 +++- .../confirmations/confirmations_state.h | 3 + 5 files changed, 483 insertions(+), 14 deletions(-) create mode 100644 vendor/bat-native-ads/data/test/confirmations_issue_16744.json diff --git a/vendor/bat-native-ads/data/test/confirmations_issue_16744.json b/vendor/bat-native-ads/data/test/confirmations_issue_16744.json new file mode 100644 index 000000000000..8948ed989898 --- /dev/null +++ b/vendor/bat-native-ads/data/test/confirmations_issue_16744.json @@ -0,0 +1,182 @@ +{ + "ads_rewards": { + "payments": [ + { + "balance": 0.28, + "month": "2021-05", + "transaction_count": "48" + }, + { + "balance": 2.8025, + "month": "2021-04", + "transaction_count": "290" + }, + { + "balance": 4.25, + "month": "2021-03", + "transaction_count": "342" + }, + { + "balance": 6.73, + "month": "2021-02", + "transaction_count": "420" + }, + { + "balance": 5.775, + "month": "2021-01", + "transaction_count": "432" + }, + { + "balance": 5.475, + "month": "2020-12", + "transaction_count": "180" + }, + { + "balance": 5.405, + "month": "2020-11", + "transaction_count": "151" + }, + { + "balance": 0.825, + "month": "2020-10", + "transaction_count": "33" + }, + { + "balance": 1.625, + "month": "2020-09", + "transaction_count": "80" + }, + { + "balance": 6.45, + "month": "2020-08", + "transaction_count": "156" + }, + { + "balance": 12.2, + "month": "2020-07", + "transaction_count": "241" + }, + { + "balance": 11.79, + "month": "2020-06", + "transaction_count": "242" + }, + { + "balance": 12.45, + "month": "2020-05", + "transaction_count": "238" + }, + { + "balance": 15.55, + "month": "2020-04", + "transaction_count": "293" + }, + { + "balance": 15.05, + "month": "2020-03", + "transaction_count": "284" + }, + { + "balance": 7.65, + "month": "2020-02", + "transaction_count": "149" + }, + { + "balance": 3.45, + "month": "2020-01", + "transaction_count": "65" + }, + { + "balance": 5.5, + "month": "2019-12", + "transaction_count": "110" + }, + { + "balance": 2.1, + "month": "2019-11", + "transaction_count": "42" + }, + { + "balance": 6.2, + "month": "2019-10", + "transaction_count": "124" + }, + { + "balance": 7.25, + "month": "2019-09", + "transaction_count": "115" + }, + { + "balance": 13.65, + "month": "2019-08", + "transaction_count": "225" + }, + { + "balance": 6.1, + "month": "2019-07", + "transaction_count": "114" + }, + { + "balance": 12.65, + "month": "2019-06", + "transaction_count": "253" + } + ], + "unreconciled_estimated_pending_rewards": 2.8034999999999997, + "grants_balance": 169.68 + }, + "catalog_issuers": { + }, + "confirmations": { + "failed_confirmations": [] + }, + "next_token_redemption_date_in_seconds": "4102444799", + "transaction_history": { + "transactions": [ + { + "confirmation_type": "view", + "estimated_redemption_value": 0.01, + "timestamp_in_seconds": "1625096431" + }, + { + "confirmation_type": "view", + "estimated_redemption_value": 0.01, + "timestamp_in_seconds": "1625142812" + }, + { + "confirmation_type": "dismiss", + "estimated_redemption_value": 0, + "timestamp_in_seconds": "1625142813" + }, + { + "confirmation_type": "view", + "estimated_redemption_value": 0.01, + "timestamp_in_seconds": "1625142861" + }, + { + "confirmation_type": "view", + "estimated_redemption_value": 0.01, + "timestamp_in_seconds": "1625143649" + } + ] + }, + "unblinded_payment_tokens": [ + { + "public_key": "oOJO/xLaCXGW6yhpeIfM4K1X2ln7sgdjTCTCHe8BugE=", + "unblinded_token": "sd4NG8YF9jIzjqAapwO9Y+geBMh5YDdwn6jtD2PfBSye89L6s14SlMc/MLyJXb+oVwMI/ktpk7O3IlvYaxKZG4x+Rm/uDbXWjdqx8kQ7Ge1QVDvGkFdD2oAKsyiz4OYm" + }, + { + "public_key": "uor3AzFj4OmdCxwetsYD1TxPXZSw40t3j/VOCUyC7Rs=", + "unblinded_token": "CtfIk2jtylneiONnhkBDv/H4MPgOLuVzuYEHpnGU94EZ4vy2RxJJu/NrQxmkGwBvNAUUit6KmvQvgVcLFvU5ynLwKUBSiZGsnykUYbCsYwDODzZPnIFN/RzV2UidiB0o" + }, + { + "public_key": "oOJO/xLaCXGW6yhpeIfM4K1X2ln7sgdjTCTCHe8BugE=", + "unblinded_token": "I0PdV23mdq71MWCXhiIIgmrWDHR92S1gbXJRfOKtCFpuXY9+fiIlbr5Kk7iyaAP0Xkw7oLUcCQTS5g2lw0jvSKLiEuCeOMIYD8U1TF2J2r13hu7Nh1COoOEELhCnyeBe" + }, + { + "public_key": "oOJO/xLaCXGW6yhpeIfM4K1X2ln7sgdjTCTCHe8BugE=", + "unblinded_token": "hlwvI/EELm+pEJt/KCL698hhg4iQpOygzbdIUk6num1+SLNFvkQsMlH1qfu5N3CkVG+U18o/SbINieAr2ghzopTVIP4C3ZgTx5WQKjq7Czmz7J0hTmsKDShayU2JGF1I" + } + ], + "unblinded_tokens": [] +} diff --git a/vendor/bat-native-ads/data/test/confirmations_with_unblinded_tokens.json b/vendor/bat-native-ads/data/test/confirmations_with_unblinded_tokens.json index 02450ffd577b..39a6b8623c42 100644 --- a/vendor/bat-native-ads/data/test/confirmations_with_unblinded_tokens.json +++ b/vendor/bat-native-ads/data/test/confirmations_with_unblinded_tokens.json @@ -24,7 +24,13 @@ }, "next_token_redemption_date_in_seconds": "4102444799", "transaction_history": { - "transactions": [] + "transactions": [ + { + "confirmation_type": "view", + "estimated_redemption_value": 0.01, + "timestamp_in_seconds": "1625096431" + } + ] }, "unblinded_payment_tokens": [ { diff --git a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc index ac11f0c67fcc..ce2d7f511cbb 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc @@ -288,10 +288,10 @@ TEST_F( // payment balances expected_statement.estimated_pending_rewards = 4.1235; - // Calculated from the above payment balance for May + // Calculated from the above payment balance for June expected_statement.earnings_this_month = 1.8375; - // Calculated from the above payment balance for April + // Calculated from the above payment balance for May expected_statement.earnings_last_month = 1.0385; EXPECT_EQ(expected_statement, statement); @@ -300,6 +300,251 @@ TEST_F( // Assert } +TEST_F( + BatAdsAdRewardsIntegrationTest, + FailedToUpdateAdRewardsDueToNotZeroingUnreconciledEstimatedPendingRewardsIssue16744) { // NOLINT + // Arrange + const URLEndpoints endpoints = { + {"/v1/confirmation/payment/c387c2d8-a26d-4451-83e4-5c0c6fd942be", + {{net::HTTP_OK, + R"([ + { + "month": "2021-07", + "transactionCount": "5", + "balance": "0.05" + }, + { + "month": "2021-06", + "transactionCount": "234", + "balance": "1.9475" + }, + { + "month": "2021-05", + "transactionCount": "170", + "balance": "1.0385" + }, + { + "month": "2021-04", + "transactionCount": "290", + "balance": "2.8025" + }, + { + "month": "2021-03", + "transactionCount": "342", + "balance": "4.25" + }, + { + "month": "2021-02", + "transactionCount": "420", + "balance": "6.73" + }, + { + "month": "2021-01", + "transactionCount": "432", + "balance": "5.775" + }, + { + "month": "2020-12", + "transactionCount": "180", + "balance": "5.475" + }, + { + "month": "2020-11", + "transactionCount": "151", + "balance": "5.405" + }, + { + "month": "2020-10", + "transactionCount": "33", + "balance": "0.825" + }, + { + "month": "2020-09", + "transactionCount": "80", + "balance": "1.625" + }, + { + "month": "2020-08", + "transactionCount": "156", + "balance": "6.45" + }, + { + "month": "2020-07", + "transactionCount": "241", + "balance": "12.2" + }, + { + "month": "2020-06", + "transactionCount": "242", + "balance": "11.79" + }, + { + "month": "2020-05", + "transactionCount": "238", + "balance": "12.45" + }, + { + "month": "2020-04", + "transactionCount": "293", + "balance": "15.55" + }, + { + "month": "2020-03", + "transactionCount": "284", + "balance": "15.05" + }, + { + "month": "2020-02", + "transactionCount": "149", + "balance": "7.65" + }, + { + "month": "2020-01", + "transactionCount": "65", + "balance": "3.45" + }, + { + "month": "2019-12", + "transactionCount": "110", + "balance": "5.5" + }, + { + "month": "2019-11", + "transactionCount": "42", + "balance": "2.1" + }, + { + "month": "2019-10", + "transactionCount": "124", + "balance": "6.2" + }, + { + "month": "2019-09", + "transactionCount": "115", + "balance": "7.25" + }, + { + "month": "2019-08", + "transactionCount": "225", + "balance": "13.65" + }, + { + "month": "2019-07", + "transactionCount": "114", + "balance": "6.1" + }, + { + "month": "2019-06", + "transactionCount": "253", + "balance": "12.65" + } + ])"}}}, + {"/v1/promotions/ads/grants/" + "summary?paymentId=c387c2d8-a26d-4451-83e4-5c0c6fd942be", + {{net::HTTP_OK, + R"({ + "type" : "ads", + "amount" : "169.68", + "lastClaim" : "2021-05-06T20:55:56Z" + })"}}}}; + + MockUrlRequest(ads_client_mock_, endpoints); + + MockLoad(ads_client_mock_, "confirmations.json", + "confirmations_issue_16744.json"); + + InitializeAds(); + + AdvanceClock(TimeFromDateString("4 July 2021")); + + // Act + GetAds()->GetAccountStatement( + [](const bool success, const StatementInfo& statement) { + ASSERT_TRUE(success); + + StatementInfo expected_statement; + expected_statement.next_payment_date = + TimestampFromDateString("5 July 2021"); + + // Calculated by subtracting the ad grant balance from the accumulated + // payment balances + expected_statement.estimated_pending_rewards = 4.3135; + + // Calculated from the above payment balance for June + expected_statement.earnings_this_month = 0.08; + + // Calculated from the above payment balance for May + expected_statement.earnings_last_month = 1.9475; + + // Calculated from ads received during July + expected_statement.ads_received_this_month = 3; + + // Transactions + TransactionInfo transaction_1; // June 30, 2021 11:40:31 PM + transaction_1.timestamp = 1625096431; + transaction_1.estimated_redemption_value = 0.01; + transaction_1.confirmation_type = "view"; + expected_statement.transactions.push_back(transaction_1); + + TransactionInfo transaction_2; // July 1, 2021 12:33:32 PM + transaction_2.timestamp = 1625142812; + transaction_2.estimated_redemption_value = 0.01; + transaction_2.confirmation_type = "view"; + expected_statement.transactions.push_back(transaction_2); + + TransactionInfo transaction_3; // July 1, 2021 12:33:33 PM + transaction_3.timestamp = 1625142813; + transaction_3.estimated_redemption_value = 0.0; + transaction_3.confirmation_type = "dismiss"; + expected_statement.transactions.push_back(transaction_3); + + TransactionInfo transaction_4; // July 1, 2021 12:34:21 PM + transaction_4.timestamp = 1625142861; + transaction_4.estimated_redemption_value = 0.01; + transaction_4.confirmation_type = "view"; + expected_statement.transactions.push_back(transaction_4); + + TransactionInfo transaction_5; // July 1, 2021 12:47:29 PM + transaction_5.timestamp = 1625143649; + transaction_5.estimated_redemption_value = 0.01; + transaction_5.confirmation_type = "view"; + expected_statement.transactions.push_back(transaction_5); + + // Uncleared transactions + TransactionInfo uncleared_transaction_1; // July 1, 2021 12:33:32 PM + uncleared_transaction_1.timestamp = 1625142812; + uncleared_transaction_1.estimated_redemption_value = 0.01; + uncleared_transaction_1.confirmation_type = "view"; + expected_statement.uncleared_transactions.push_back( + uncleared_transaction_1); + + TransactionInfo uncleared_transaction_2; // July 1, 2021 12:33:33 PM + uncleared_transaction_2.timestamp = 1625142813; + uncleared_transaction_2.estimated_redemption_value = 0.0; + uncleared_transaction_2.confirmation_type = "dismiss"; + expected_statement.uncleared_transactions.push_back( + uncleared_transaction_2); + + TransactionInfo uncleared_transaction_3; // July 1, 2021 12:34:21 PM + uncleared_transaction_3.timestamp = 1625142861; + uncleared_transaction_3.estimated_redemption_value = 0.01; + uncleared_transaction_3.confirmation_type = "view"; + expected_statement.uncleared_transactions.push_back( + uncleared_transaction_3); + + TransactionInfo uncleared_transaction_4; // July 1, 2021 12:47:29 PM + uncleared_transaction_4.timestamp = 1625143649; + uncleared_transaction_4.estimated_redemption_value = 0.01; + uncleared_transaction_4.confirmation_type = "view"; + expected_statement.uncleared_transactions.push_back( + uncleared_transaction_4); + + EXPECT_EQ(expected_statement, statement); + }); + + // Assert +} + TEST_F(BatAdsAdRewardsIntegrationTest, GetAdRewardsFromEndPoints) { // Arrange const URLEndpoints endpoints = { diff --git a/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.cc b/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.cc index 0582b111ffd5..ee1a941a1aaa 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.cc @@ -256,14 +256,14 @@ bool ConfirmationsState::FromJson(const std::string& json) { BLOG(1, "Failed to parse failed confirmations"); } - if (!ParseAdRewardsFromDictionary(dictionary)) { - BLOG(1, "Failed to parse ad rewards"); - } - if (!ParseTransactionsFromDictionary(dictionary)) { BLOG(1, "Failed to parse transactions"); } + if (!ParseAdRewardsFromDictionary(dictionary)) { + BLOG(1, "Failed to parse ad rewards"); + } + if (!ParseUnblindedTokensFromDictionary(dictionary)) { BLOG(1, "Failed to parse unblinded tokens"); } @@ -676,19 +676,52 @@ bool ConfirmationsState::ParseAdRewardsFromDictionary( return false; } - const base::Value* unblinded_tokens = - dictionary->FindListKey("unblinded_payment_tokens"); - if (unblinded_tokens && unblinded_tokens->GetList().empty()) { - // Migration path for https://github.com/brave/brave-browser/issues/16678 - ad_rewards_dictionary->SetDoubleKey( - "unreconciled_estimated_pending_rewards", 0.0); - } + // Migration path for https://github.com/brave/brave-browser/issues/16678 and + // https://github.com/brave/brave-browser/issues/16744 + const double value = GetUnreconciledEstimatedPendingRewards(dictionary); + ad_rewards_dictionary->SetDoubleKey("unreconciled_estimated_pending_rewards", + value); ad_rewards_->SetFromDictionary(ad_rewards_dictionary); return true; } +double ConfirmationsState::GetUnreconciledEstimatedPendingRewards( + base::DictionaryValue* dictionary) { + DCHECK(dictionary); + + const base::Value* unblinded_payment_tokens = + dictionary->FindListKey("unblinded_payment_tokens"); + if (!unblinded_payment_tokens) { + return 0.0; + } + + size_t count = unblinded_payment_tokens->GetList().size(); + if (count == 0) { + // There are no uncleared unblinded payment tokens to redeem + return 0.0; + } + + // Uncleared transactions are always at the end of the transaction history + if (transactions_.size() < count) { + // There are fewer transactions than unblinded payment tokens which is + // likely due to manually editing transactions in confirmations.json + NOTREACHED(); + count = transactions_.size(); + } + + const TransactionList transactions(transactions_.end() - count, + transactions_.end()); + + double value = 0.0; + for (const auto& transaction : transactions) { + value += transaction.estimated_redemption_value; + } + + return value; +} + bool ConfirmationsState::ParseUnblindedTokensFromDictionary( base::DictionaryValue* dictionary) { DCHECK(dictionary); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.h b/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.h index ee7f884824ba..112482fcc7d5 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/account/confirmations/confirmations_state.h @@ -90,6 +90,9 @@ class ConfirmationsState { bool ParseAdRewardsFromDictionary(base::DictionaryValue* dictionary); + double GetUnreconciledEstimatedPendingRewards( + base::DictionaryValue* dictionary); + std::unique_ptr unblinded_tokens_; bool ParseUnblindedTokensFromDictionary(base::DictionaryValue* dictionary);