Skip to content
This repository has been archived by the owner on Jul 15, 2022. It is now read-only.

Commit

Permalink
LL-4373 Discard existing ops on sync if blacklist has changed (#1010)
Browse files Browse the repository at this point in the history
* LL-4373 Discard existing ops on sync if blacklist has changed

Add testing for blacklisted feature

* update tests

* snapshot

Co-authored-by: Gaëtan Renaudeau <[email protected]>
  • Loading branch information
juan-cortes and gre authored Jan 15, 2021
1 parent 7bd5015 commit c51eac8
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 8 deletions.
115 changes: 115 additions & 0 deletions src/__tests__/__snapshots__/all.libcore.js.snap

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/__tests__/currencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ test("sort by marketcap", () => {
"bitcoin",
"ethereum",
"ethereum/erc20/0x_project",
"stealthcoin",
"ethereum/erc20/holotoken",
"stealthcoin",
"ethereum/erc20/hydro_protocol",
"ethereum/erc20/xensor",
]);
Expand Down
2 changes: 0 additions & 2 deletions src/__tests__/test-helpers/libcore-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import "./setup";
import { setEnvUnsafe } from "../../env";
import implementLibcore from "../../libcore/platforms/nodejs";

jest.setTimeout(180000);

let setupCalled = null;
export const setup = (testId) => {
if (setupCalled) {
Expand Down
2 changes: 0 additions & 2 deletions src/__tests__/test-helpers/libcore-setup.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { listen } from "@ledgerhq/logs";
import "./setup";
import "./implement-react-native-libcore";

jest.setTimeout(180000);

export const setup = (testName) => {
global._JEST_SETUP(testName);
};
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/test-helpers/setup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { setSupportedCurrencies } from "../../currencies";

jest.setTimeout(180000);

setSupportedCurrencies([
"bitcoin",
"ethereum",
Expand Down
4 changes: 4 additions & 0 deletions src/account/serialization.js
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ export function fromAccountRaw(rawAccount: AccountRaw): Account {
bitcoinResources,
swapHistory,
algorandResources,
blacklistedTokensCache,
polkadotResources,
} = rawAccount;

Expand Down Expand Up @@ -632,6 +633,7 @@ export function fromAccountRaw(rawAccount: AccountRaw): Account {
currency,
lastSyncDate: new Date(lastSyncDate || 0),
swapHistory: [],
blacklistedTokensCache,
};

if (xpub) {
Expand Down Expand Up @@ -701,6 +703,7 @@ export function toAccountRaw({
bitcoinResources,
swapHistory,
algorandResources,
blacklistedTokensCache,
polkadotResources,
}: Account): AccountRaw {
const res: $Exact<AccountRaw> = {
Expand All @@ -714,6 +717,7 @@ export function toAccountRaw({
freshAddressPath,
freshAddresses,
blockHeight,
blacklistedTokensCache,
creationDate: creationDate.toISOString(),
operationsCount,
operations: (operations || []).map((o) => toOperationRaw(o)),
Expand Down
3 changes: 1 addition & 2 deletions src/families/ethereum/modules/compound.resilience.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// @flow
import "../../../__tests__/test-helpers/setup";
import { reduce } from "rxjs/operators";
import { setSupportedCurrencies } from "../../../currencies";
import { fromAccountRaw, toAccountRaw } from "../../../account";
import type { Account } from "../../../types";
import { getAccountBridge } from "../../../bridge";
import { makeBridgeCacheSystem } from "../../../bridge/cache";
import { ethereum1 } from "../test-dataset";
import { setEnv } from "../../../env";

setSupportedCurrencies(["ethereum"]);
setEnv("COMPOUND_API", "https://status.ledger.com"); // hack to hit an endpoint that actually is going to 404

test("if API is down, an account still sync fine", async () => {
Expand Down
9 changes: 8 additions & 1 deletion src/families/ethereum/synchronisation.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,16 @@ export const getAccountShape: GetAccountShape = async (

// fetch transactions, incrementally if possible
const mostRecentStableOperation = initialStableOperations[0];

const newBlacklistedTokensCache = JSON.stringify(blacklistedTokenIds || []);
const outdatedBlacklist =
initialAccount?.blacklistedTokensCache !== newBlacklistedTokensCache;

let pullFromBlockHash =
initialAccount &&
areAllOperationsLoaded(initialAccount) &&
mostRecentStableOperation
mostRecentStableOperation &&
!outdatedBlacklist
? mostRecentStableOperation.blockHash
: undefined;

Expand Down Expand Up @@ -159,6 +165,7 @@ export const getAccountShape: GetAccountShape = async (
blockHeight,
lastSyncDate: new Date(),
balanceHistory: undefined,
blacklistedTokensCache: newBlacklistedTokensCache,
};

return accountShape;
Expand Down
95 changes: 95 additions & 0 deletions src/families/ethereum/synchronisation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// @flow
import "../../__tests__/test-helpers/setup";
import { reduce } from "rxjs/operators";
import { fromAccountRaw } from "../../account";
import { getAccountCurrency } from "../../account/helpers";
import type { Account } from "../../types";
import { getAccountBridge } from "../../bridge";
import { makeBridgeCacheSystem } from "../../bridge/cache";
import { ethereum1 } from "./test-dataset";

describe("blacklistedTokenIds functionality", () => {
const account = fromAccountRaw(ethereum1);
let localCache = {};
const cache = makeBridgeCacheSystem({
saveData(c, d) {
localCache[c.id] = d;
return Promise.resolve();
},
getData(c) {
return Promise.resolve(localCache[c.id]);
},
});

test("initial raw account contains no token accounts", async () => {
await cache.prepareCurrency(account.currency);
expect(ethereum1.subAccounts?.length).toBeFalsy();
});

test("sync finds tokens, but not blacklisted ones", async () => {
const bridge = getAccountBridge(account);
const blacklistedTokenIds = ["ethereum/erc20/weth"];
const synced = await bridge
.sync(account, {
paginationConfig: {},
blacklistedTokenIds,
})
.pipe(reduce((a, f: (Account) => Account) => f(a), account))
.toPromise();

// Contains token accounts
expect(synced.subAccounts?.length).toBeTruthy();

// Contains a known token
expect(
synced.subAccounts.find(
(a) => getAccountCurrency(a)?.id === "ethereum/erc20/0x_project"
)
).toBeTruthy();

// Does not contain a blacklisted token
expect(
synced.subAccounts.find((a) =>
blacklistedTokenIds.includes(getAccountCurrency(a)?.id)
)
).toBe(undefined);
});

test("account resyncs tokens if no longer blacklisted", async () => {
const bridge = getAccountBridge(account);
const blacklistedTokenIds = ["ethereum/erc20/weth"];
const syncedWithoutWeth = await bridge
.sync(account, {
paginationConfig: {},
blacklistedTokenIds,
})
.pipe(reduce((a, f: (Account) => Account) => f(a), account))
.toPromise();

// Contains token accounts
expect(syncedWithoutWeth.subAccounts?.length).toBeTruthy();

// Does not contain a blacklisted token
expect(
syncedWithoutWeth.subAccounts.find((a) =>
blacklistedTokenIds.includes(getAccountCurrency(a)?.id)
)
).toBe(undefined);

//Sync again with `syncedWithoutWeth` as a base but without it being blacklisted
const synced = await bridge
.sync(account, {
paginationConfig: {},
blacklistedTokenIds: ["ethereum/erc20/somethingElse"],
})
.pipe(reduce((a, f: (Account) => Account) => f(a), account))
.toPromise();

// Does not contain a blacklisted token
expect(
synced.subAccounts.find(
(a) => getAccountCurrency(a)?.id === "ethereum/erc20/weth"
)
).toBeTruthy();
});
});
5 changes: 5 additions & 0 deletions src/reconciliation.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ export function patchAccount(
changed = true;
}

if (account.blacklistedTokensCache !== updatedRaw.blacklistedTokensCache) {
next.blacklistedTokensCache = updatedRaw.blacklistedTokensCache;
changed = true;
}

if (
updatedRaw.tronResources &&
account.tronResources !== updatedRaw.tronResources
Expand Down
4 changes: 4 additions & 0 deletions src/types/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ export type Account = {

// Swap operations linked to this account
swapHistory: SwapOperation[],

// Hash used to discard tx history on sync if blacklisted token ids change
blacklistedTokensCache?: string,
};

export type SubAccount = TokenAccount | ChildAccount;
Expand Down Expand Up @@ -279,6 +282,7 @@ export type AccountRaw = {
polkadotResources?: PolkadotResourcesRaw,
// Swap operations linked to this account
swapHistory?: SwapOperationRaw[],
blacklistedTokensCache?: string,
};

export type SubAccountRaw = TokenAccountRaw | ChildAccountRaw;
Expand Down

1 comment on commit c51eac8

@vercel
Copy link

@vercel vercel bot commented on c51eac8 Jan 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.