Skip to content

Commit

Permalink
Merge pull request #610 from golemfactory/feature/JST-468/make-use-of…
Browse files Browse the repository at this point in the history
…-public-whitelist

Feature/jst 468/make use of public whitelist
  • Loading branch information
grisha87 authored Oct 18, 2023
2 parents f41abd4 + ffe3c47 commit fd57fdd
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 23 deletions.
76 changes: 57 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@

<!-- TOC -->

- [Golem JavaScript API](#golem-javascript-api)
- [Table of contents](#table-of-contents)
- [What's Golem and `golem-js`?](#whats-golem-and-golem-js)
- [Golem application development](#golem-application-development)
- [Installation](#installation)
- [Building](#building)
- [Usage](#usage)
- [Node.js context](#nodejs-context)
- [Web Browser context](#web-browser-context)
- [Testing](#testing)
- [Running unit tests](#running-unit-tests)
- [Running E2E tests](#running-e2e-tests)
- [NodeJS](#execute-the-e2e-tests)
- [Cypress](#execute-the-cypress-tests)
- [Contributing](#contributing)
- [Controlling interactions and costs](#controlling-interactions-and-costs)
- [See also](#see-also)
<!-- TOC -->
- [Table of contents](#table-of-contents)
- [What's Golem and `golem-js`?](#whats-golem-and-golem-js)
- [Golem application development](#golem-application-development)
- [Installation](#installation)
- [Building](#building)
- [Usage](#usage)
- [Node.js context](#nodejs-context)
- [Web Browser context](#web-browser-context)
- [Testing](#testing)
- [Running unit tests](#running-unit-tests)
- [Running E2E tests](#running-e2e-tests)
- [NodeJS](#execute-the-e2e-tests)
- [Cypress](#execute-the-cypress-tests)
- [Contributing](#contributing)
- [Controlling interactions and costs](#controlling-interactions-and-costs)
- [Limit price limits to filter out offers that are too expensive](#limit-price-limits-to-filter-out-offers-that-are-too-expensive)
- [Work with reliable providers](#work-with-reliable-providers)
- [See also](#see-also)
<!-- TOC -->

![GitHub](https://img.shields.io/github/license/golemfactory/golem-js)
![npm](https://img.shields.io/npm/v/@golem-sdk/golem-js)
Expand Down Expand Up @@ -200,7 +201,9 @@ that they define. As a Requestor, you might want to:
like to avoid

To make this easy, we provided you with a set of predefined market proposal filters, which you can combine to implement
your own market strategy. For example:
your own market strategy.

### Limit price limits to filter out offers that are too expensive

```typescript
import { TaskExecutor, ProposalFilters } from "@golem-sdk/golem-js";
Expand All @@ -226,6 +229,41 @@ const executor = await TaskExecutor.create({

To learn more about other filters, please check the [API reference of the market/strategy module](https://docs.golem.network/docs/golem-js/reference/modules/market_strategy)

### Work with reliable providers

The `getHealthyProvidersWhiteList` helper will provide you with a list of Provider ID's that were checked with basic health-checks. Using this whitelist will increase the chance of working with a reliable provider. Please note, that you can also build up your own list of favourite providers and use it in a similar fashion.

```typescript
import { TaskExecutor, ProposalFilters, MarketHelpers } from "@golem-sdk/golem-js";

// Prepare the price filter
const acceptablePrice = ProposalFilters.limitPriceFilter({
start: 1,
cpuPerSec: 1 / 3600,
envPerSec: 1 / 3600,
});

// Collect the whitelist
const verifiedProviders = await MarketHelpers.getHealthyProvidersWhiteList();

// Prepare the whitelist filter
const whiteList = ProposalFilters.whiteListProposalIdsFilter(verifiedProviders);

const executor = await TaskExecutor.create({
// What do you want to run
package: "golem/alpine:3.18.2",

// How much you wish to spend
budget: 0.5,
proposalFilter: async (proposal) => (await acceptablePrice(proposal)) && (await whiteList(proposal)),

// Where you want to spend
payment: {
network: "polygon",
},
});
```

## See also

- [Golem](https://golem.network), a global, open-source, decentralized supercomputer that anyone can access.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"devDependencies": {
"@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.7.0",
"@johanblumenberg/ts-mockito": "^1.0.39",
"@rollup/plugin-alias": "^5.0.0",
"@rollup/plugin-commonjs": "^25.0.3",
"@rollup/plugin-json": "^6.0.0",
Expand All @@ -77,7 +78,7 @@
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"buffer": "^6.0.3",
"cypress": "13.2.0",
"cypress": "13.3.1",
"eslint": "~8.50.0",
"eslint-config-prettier": "^9.0.0",
"express": "^4.18.2",
Expand Down
7 changes: 5 additions & 2 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default [
commonjs(),
nodePolyfills(),
json(), // Required because one our dependencies (bottleneck) loads its own 'version.json'
typescript({ tsconfig: "./tsconfig.json" }),
typescript({ tsconfig: "./tsconfig.json", exclude: ["**/__tests__", "**/*.test.ts"] }),
terser({ keep_classnames: true }),
filesize({ reporter: [sizeValidator, "boxen"] }),
],
Expand All @@ -54,7 +54,10 @@ export default [
{ file: pkg.main, format: "cjs", sourcemap: true },
{ file: pkg.module, format: "es", sourcemap: true },
],
plugins: [typescript({ tsconfig: "./tsconfig.json" }), filesize({ reporter: [sizeValidator, "boxen"] })],
plugins: [
typescript({ tsconfig: "./tsconfig.json", exclude: ["**/__tests__", "**/*.test.ts"] }),
filesize({ reporter: [sizeValidator, "boxen"] }),
],
},
];

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export {
} from "./storage";
export { ActivityStateEnum, Result } from "./activity";
export { AgreementCandidate, AgreementSelectors } from "./agreement";
export { ProposalFilters, ProposalFilter } from "./market";
export { ProposalFilters, ProposalFilter, MarketHelpers } from "./market";
export { Package, PackageOptions } from "./package";
export { PaymentFilters } from "./payment";
export { Events, BaseEvent, EventType } from "./events";
Expand Down
55 changes: 55 additions & 0 deletions src/market/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { MockPropertyPolicy, imock, instance, when } from "@johanblumenberg/ts-mockito";

import { getHealthyProvidersWhiteList } from "./helpers";

const mockFetch = jest.spyOn(global, "fetch");
const response = imock<Response>();

beforeEach(() => {
jest.resetAllMocks();
});

describe("Market Helpers", () => {
describe("Getting public healthy providers whitelist", () => {
describe("Positive cases", () => {
test("Will return the list returned by the endpoint", async () => {
// Given
when(response.json()).thenResolve(["0xAAA", "0xBBB"]);
mockFetch.mockResolvedValue(instance(response));

// When
const data = await getHealthyProvidersWhiteList();

// Then
expect(data).toEqual(["0xAAA", "0xBBB"]);
});
});

describe("Negative cases", () => {
test("It throws an error when the response from the API will not be a successful one (fetch -> response.ok)", async () => {
// Given
const mockResponse = imock<Response>(MockPropertyPolicy.StubAsProperty);
when(mockResponse.ok).thenReturn(false);
when(mockResponse.text()).thenResolve("{error:'test'}");
mockFetch.mockResolvedValue(instance(mockResponse));

// When, Then
await expect(() => getHealthyProvidersWhiteList()).rejects.toThrow(
"Failed to download healthy provider whitelist due to an error: Error: Request to download healthy provider whitelist failed: {error:'test'}",
);
});

test("It throws an error when executing of fetch will fail for any reason", async () => {
// Given
mockFetch.mockImplementation(() => {
throw new Error("Something went wrong really bad!");
});

// When, Then
await expect(() => getHealthyProvidersWhiteList()).rejects.toThrow(
"Failed to download healthy provider whitelist due to an error: Error: Something went wrong really bad!",
);
});
});
});
});
22 changes: 22 additions & 0 deletions src/market/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Helps to obtain a whitelist of providers which were health-tested.
*
* Important: This helper requires internet access to function properly.
*
* @return An array with Golem Node IDs of the whitelisted providers.
*/
export async function getHealthyProvidersWhiteList(): Promise<string[]> {
try {
const response = await fetch("https://provider-health.golem.network/v1/provider-whitelist");

if (response.ok) {
return response.json();
} else {
const body = await response.text();

throw new Error(`Request to download healthy provider whitelist failed: ${body}`);
}
} catch (err) {
throw new Error(`Failed to download healthy provider whitelist due to an error: ${err}`);
}
}
1 change: 1 addition & 0 deletions src/market/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { Proposal, ProposalDetails } from "./proposal";
export { MarketDecoration } from "./builder";
export { DemandConfig } from "./config";
export * as ProposalFilters from "./strategy";
export * as MarketHelpers from "./helpers";

0 comments on commit fd57fdd

Please sign in to comment.