Skip to content

Commit

Permalink
Merge pull request #932 from golemfactory/feature/JST-901/allocation-…
Browse files Browse the repository at this point in the history
…demand-second-marriage

Fetch payment related properties and constraints from yagna
  • Loading branch information
SewerynKras authored May 21, 2024
2 parents 75b37f8 + 8609356 commit 29a47b7
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 114 deletions.
11 changes: 5 additions & 6 deletions examples/basic/hello-world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ import { pinoPrettyLogger } from "@golem-sdk/pino-logger";
logger,
});

const payerDetails = await glm.payment.getPayerDetails();
const demandSpecification = await glm.market.buildDemandDetails(demand.demand, payerDetails);
const allocation = await glm.payment.createAllocation({
budget: glm.market.estimateBudget(demand),
expirationSec: 60 * 60, // 60 minutes
});
const demandSpecification = await glm.market.buildDemandDetails(demand.demand, allocation);
const proposal$ = glm.market.startCollectingProposals({
demandSpecification,
bufferSize: 15,
Expand All @@ -51,10 +54,6 @@ import { pinoPrettyLogger } from "@golem-sdk/pino-logger";

const agreement = await glm.market.proposeAgreement(draftProposal);

const allocation = await glm.payment.createAllocation({
budget: glm.market.estimateBudget(demand),
expirationSec: 60 * 60, // 60 minutes
});
const lease = await glm.market.createLease(agreement, allocation);
const activity = await glm.activity.createActivity(agreement);

Expand Down
12 changes: 6 additions & 6 deletions examples/local-image/serveLocalGvmi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ const getImagePath = (path: string) => fileURLToPath(new URL(path, import.meta.u
logger,
});

const payerDetails = await glm.payment.getPayerDetails();
const demandSpecification = await glm.market.buildDemandDetails(demand.demand, payerDetails);
const allocation = await glm.payment.createAllocation({
budget: 1,
expirationSec: 30 * 60, // 30 minutes
});
const demandSpecification = await glm.market.buildDemandDetails(demand.demand, allocation);
const proposal$ = glm.market.startCollectingProposals({
demandSpecification,
bufferSize: 15,
Expand All @@ -50,10 +53,7 @@ const getImagePath = (path: string) => fileURLToPath(new URL(path, import.meta.u
const draftProposal = await proposalPool.acquire();

const agreement = await glm.market.proposeAgreement(draftProposal);
const allocation = await glm.payment.createAllocation({
budget: 1,
expirationSec: 30 * 60, // 30 minutes
});

const lease = await glm.market.createLease(agreement, allocation);
const activity = await glm.activity.createActivity(agreement);

Expand Down
61 changes: 0 additions & 61 deletions examples/market/scan.ts

This file was deleted.

3 changes: 1 addition & 2 deletions examples/pool/hello-world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ const demandOptions = {
allocation = await glm.payment.createAllocation({ budget: 1, expirationSec: RENT_HOURS * 60 * 60 });

const proposalPool = new DraftOfferProposalPool({ minCount: 1 });
const payerDetails = await glm.payment.getPayerDetails();
const demandSpecification = await glm.market.buildDemandDetails(demandOptions.demand, payerDetails);
const demandSpecification = await glm.market.buildDemandDetails(demandOptions.demand, allocation);

const proposals$ = glm.market.startCollectingProposals({
demandSpecification,
Expand Down
4 changes: 1 addition & 3 deletions src/deployment/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ export class Deployment {

await this.dataTransferProtocol.init();

const payerDetails = await this.modules.payment.getPayerDetails();

for (const network of this.components.networks) {
const networkInstance = await Network.create(this.yagnaApi, network.options);
this.networks.set(network.name, networkInstance);
Expand All @@ -161,7 +159,7 @@ export class Deployment {
for (const pool of this.components.activityPools) {
const { demandBuildOptions, leaseProcessPoolOptions } = this.prepareParams(pool.options);

const demandSpecification = await this.modules.market.buildDemandDetails(demandBuildOptions.demand, payerDetails);
const demandSpecification = await this.modules.market.buildDemandDetails(demandBuildOptions.demand, allocation);
const proposalPool = new DraftOfferProposalPool();

const proposalSubscription = this.modules.market
Expand Down
5 changes: 1 addition & 4 deletions src/golem-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,12 @@ export class GolemNetwork {
logger: this.logger,
});

const payerDetails = await this.payment.getPayerDetails();
const demandSpecification = await this.market.buildDemandDetails(demand.demand, payerDetails);

const budget = this.market.estimateBudget(demand);

const allocation = await this.payment.createAllocation({
budget,
expirationSec: demand.market.rentHours * 60 * 60,
});
const demandSpecification = await this.market.buildDemandDetails(demand.demand, allocation);

const proposalSubscription = this.market
.startCollectingProposals({
Expand Down
9 changes: 9 additions & 0 deletions src/market/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Observable } from "rxjs";
import { Demand, DemandSpecification } from "./demand";
import YaTsClient from "ya-ts-client";
import { OfferProposal } from "./offer-proposal";
import { DemandBodyPrototype } from "./demand/demand-body-builder";

export type NewProposalEvent = YaTsClient.MarketApi.ProposalEventDTO;
export type ProposalRejectedEvent = YaTsClient.MarketApi.ProposalRejectedEventDTO;
Expand Down Expand Up @@ -41,4 +42,12 @@ export interface MarketApi {
* @param reason User readable reason that should be presented to the Provider
*/
rejectProposal(receivedProposal: OfferProposal, reason: string): Promise<void>;

/**
* Fetches payment related decorations, based on the given allocation ID.
*
* @param allocationId The ID of the allocation that will be used to pay for computations related to the demand
*
*/
getPaymentRelatedDemandDecorations(allocationId: string): Promise<DemandBodyPrototype>;
}
22 changes: 10 additions & 12 deletions src/market/demand/directors/payment-demand-director.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
import { PayerDetails } from "../../../payment/PayerDetails";
import { ComparisonOperator, DemandBodyBuilder } from "../demand-body-builder";
import { DemandBodyBuilder } from "../demand-body-builder";
import { IDemandDirector } from "../../market.module";
import { PaymentDemandDirectorConfig } from "./payment-demand-director-config";
import { Allocation } from "../../../payment";
import { MarketApi } from "../../api";

export class PaymentDemandDirector implements IDemandDirector {
constructor(
private payerDetails: PayerDetails,
private allocation: Allocation,
private marketApiAdapter: MarketApi,
private config: PaymentDemandDirectorConfig = new PaymentDemandDirectorConfig(),
) {}

apply(builder: DemandBodyBuilder) {
async apply(builder: DemandBodyBuilder) {
// Configure mid-agreement payments
builder
.addProperty("golem.com.scheme.payu.debit-note.interval-sec?", this.config.midAgreementDebitNoteIntervalSec)
.addProperty("golem.com.scheme.payu.payment-timeout-sec?", this.config.midAgreementPaymentTimeoutSec)
.addProperty("golem.com.payment.debit-notes.accept-timeout?", this.config.debitNotesAcceptanceTimeoutSec);

// Configure payment platform
builder
.addProperty(
`golem.com.payment.platform.${this.payerDetails.getPaymentPlatform()}.address`,
this.payerDetails.address,
)
.addConstraint(`golem.com.payment.platform.${this.payerDetails.getPaymentPlatform()}.address`, "*")
.addProperty("golem.com.payment.protocol.version", "2")
.addConstraint("golem.com.payment.protocol.version", "1", ComparisonOperator.Gt);
const { constraints, properties } = await this.marketApiAdapter.getPaymentRelatedDemandDecorations(
this.allocation.id,
);
builder.mergePrototype({ constraints, properties });
}
}
28 changes: 23 additions & 5 deletions src/market/market.module.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import { from, of, take, takeUntil, timer } from "rxjs";
import { IProposalRepository, OfferProposal, ProposalProperties } from "./offer-proposal";
import { MarketApiAdapter } from "../shared/yagna/";
import { IAgreementApi } from "../agreement/agreement";
import { PayerDetails } from "../payment/PayerDetails";
import { IActivityApi, IFileServer } from "../activity";
import { StorageProvider } from "../shared/storage";
import { GolemMarketError } from "./error";
import { IPaymentApi } from "../payment";
import { Allocation, IPaymentApi } from "../payment";

const mockMarketApiAdapter = mock(MarketApiAdapter);
const mockYagna = mock(YagnaApi);
Expand All @@ -38,7 +37,26 @@ beforeEach(() => {
describe("Market module", () => {
describe("buildDemand()", () => {
it("should build a demand", async () => {
const payerDetails = new PayerDetails("holesky", "erc20", "0x123");
const allocation = {
id: "allocation-id",
paymentPlatform: "erc20-holesky-tglm",
} as Allocation;
when(mockMarketApiAdapter.getPaymentRelatedDemandDecorations("allocation-id")).thenResolve({
properties: [
{
key: "golem.com.payment.platform.erc20-holesky-tglm.address",
value: "0x123",
},
{
key: "golem.com.payment.protocol.version",
value: "2",
},
],
constraints: [
"(golem.com.payment.platform.erc20-holesky-tglm.address=*)",
"(golem.com.payment.protocol.version>1)",
],
});

const demandSpecification = await marketModule.buildDemandDetails(
{
Expand All @@ -55,7 +73,7 @@ describe("Market module", () => {
midAgreementPaymentTimeoutSec: 42,
},
},
payerDetails,
allocation,
);

const expectedConstraints = [
Expand Down Expand Up @@ -113,7 +131,7 @@ describe("Market module", () => {
},
];

expect(demandSpecification.paymentPlatform).toBe(payerDetails.getPaymentPlatform());
expect(demandSpecification.paymentPlatform).toBe(allocation.paymentPlatform);
expect(demandSpecification.expirationSec).toBe(42);
expect(demandSpecification.prototype.constraints).toEqual(expect.arrayContaining(expectedConstraints));
expect(demandSpecification.prototype.properties).toEqual(expectedProperties);
Expand Down
19 changes: 7 additions & 12 deletions src/market/market.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { DemandBodyBuilder } from "./demand/demand-body-builder";
import { IAgreementApi } from "../agreement/agreement";
import { BuildDemandOptions, DemandSpecification, IDemandRepository } from "./demand";
import { ProposalsBatch } from "./proposals_batch";
import { PayerDetails } from "../payment/PayerDetails";
import { IActivityApi, IFileServer } from "../activity";
import { StorageProvider } from "../shared/storage";
import { ActivityDemandDirectorConfig } from "./demand/directors/activity-demand-director-config";
Expand Down Expand Up @@ -91,12 +90,12 @@ export interface MarketModule {
events: EventEmitter<MarketEvents>;

/**
* Build a DemandSpecification based on the given options and payer details.
* You can obtain the payer details from the payment module.
* Build a DemandSpecification based on the given options and allocation.
* You can obtain an allocation using the payment module.
* The method returns a DemandSpecification that can be used to publish the demand to the market,
* for example using the `publishDemand` method.
*/
buildDemandDetails(options: BuildDemandOptions, payerDetails: PayerDetails): Promise<DemandSpecification>;
buildDemandDetails(options: BuildDemandOptions, allocation: Allocation): Promise<DemandSpecification>;

/**
* Publishes the demand to the market and handles refreshing it when needed.
Expand Down Expand Up @@ -223,7 +222,7 @@ export class MarketModuleImpl implements MarketModule {
this.fileServer = deps.fileServer;
}

async buildDemandDetails(options: BuildDemandOptions, payerDetails: PayerDetails): Promise<DemandSpecification> {
async buildDemandDetails(options: BuildDemandOptions, allocation: Allocation): Promise<DemandSpecification> {
const builder = new DemandBodyBuilder();

// Instruct the builder what's required
Expand All @@ -240,14 +239,10 @@ export class MarketModuleImpl implements MarketModule {
await workloadDirector.apply(builder);

const paymentConfig = new PaymentDemandDirectorConfig(options.payment);
const paymentDirector = new PaymentDemandDirector(payerDetails, paymentConfig);
paymentDirector.apply(builder);
const paymentDirector = new PaymentDemandDirector(allocation, this.deps.marketApi, paymentConfig);
await paymentDirector.apply(builder);

const spec = new DemandSpecification(
builder.getProduct(),
payerDetails.getPaymentPlatform(),
basicConfig.expirationSec,
);
const spec = new DemandSpecification(builder.getProduct(), allocation.paymentPlatform, basicConfig.expirationSec);

return spec;
}
Expand Down
4 changes: 4 additions & 0 deletions src/shared/yagna/adapters/market-api-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,8 @@ export class MarketApiAdapter implements MarketApi {

return { constraints, properties };
}

public async getPaymentRelatedDemandDecorations(allocationId: string): Promise<DemandBodyPrototype> {
return this.yagnaApi.payment.getDemandDecorations([allocationId]);
}
}
4 changes: 1 addition & 3 deletions tests/e2e/leaseProcessPool.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Allocation, DraftOfferProposalPool, GolemNetwork, YagnaApi } from "../.

describe("LeaseProcessPool", () => {
const glm = new GolemNetwork();
const yagnaApi = new YagnaApi();
const modules = {
market: glm.market,
activity: glm.activity,
Expand All @@ -25,14 +24,13 @@ describe("LeaseProcessPool", () => {

beforeEach(async () => {
proposalPool = new DraftOfferProposalPool();
const payerDetails = await modules.payment.getPayerDetails();
const demandSpecification = await modules.market.buildDemandDetails(
{
activity: {
imageTag: "golem/alpine:latest",
},
},
payerDetails,
allocation,
);
proposalSubscription = proposalPool.readFrom(
modules.market.startCollectingProposals({
Expand Down

0 comments on commit 29a47b7

Please sign in to comment.