diff --git a/src/market/config.ts b/src/market/config.ts index f23645e6e..176938ebd 100644 --- a/src/market/config.ts +++ b/src/market/config.ts @@ -10,6 +10,7 @@ const DEFAULTS = { offerFetchingIntervalSec: 20, expirationSec: 30 * 60, // 30 min debitNotesAcceptanceTimeoutSec: 2 * 60, // 2 minutes + midAgreementDebitNoteIntervalSec: 2 * 60, // 2 minutes midAgreementPaymentTimeoutSec: 12 * 60 * 60, // 12 hours proposalFilter: acceptAllProposalFilter(), }; @@ -26,6 +27,7 @@ export class DemandConfig { public readonly logger?: Logger; public readonly eventTarget?: EventTarget; public readonly debitNotesAcceptanceTimeoutSec: number; + public readonly midAgreementDebitNoteIntervalSec: number; public readonly midAgreementPaymentTimeoutSec: number; constructor(options?: DemandOptions) { @@ -49,6 +51,13 @@ export class DemandConfig { throw new Error("The debit note acceptance timeout time has to be a positive integer"); } + this.midAgreementDebitNoteIntervalSec = + options?.midAgreementDebitNoteIntervalSec ?? DEFAULTS.midAgreementDebitNoteIntervalSec; + + if (!this.isPositiveInt(this.midAgreementDebitNoteIntervalSec)) { + throw new Error("The debit note interval time has to be a positive integer"); + } + this.midAgreementPaymentTimeoutSec = options?.midAgreementPaymentTimeoutSec ?? DEFAULTS.midAgreementPaymentTimeoutSec; diff --git a/src/market/demand.ts b/src/market/demand.ts index 36a936cdc..cfb61592c 100644 --- a/src/market/demand.ts +++ b/src/market/demand.ts @@ -52,16 +52,31 @@ export interface DemandOptions { eventTarget?: EventTarget; /** - * Maximum time for debit note acceptance (in seconds) + * Maximum time for allowed provider-sent debit note acceptance (in seconds) + * + * Accepting debit notes from the provider is used as a health-check of the agreement between these parties. + * Failing to accept 5 debit notes in a row will be considered as a valida reason to terminate the agreement earlier + * than {@link expirationSec} defines. + * + * _Accepting debit notes during a long activity is considered a good practice in Golem Network._ + * The SDK will accept debit notes each 2 minutes by default. + */ + debitNotesAcceptanceTimeoutSec?: number; + + /** + * The interval between provider sent debit notes to negotiate. * * If it would not be defined, the activities created for your demand would * probably live only 30 minutes, as that's the default value that the providers use to control engagements * that are not using mid-agreement payments. * - * _Accepting debit notes during a long activity is considered a good practice in Golem Network._ - * The SDK will accept debit notes each 2 minutes. + * As a requestor, you don't have to specify it, as the provider will propose a value that the SDK will simply + * accept without negotiations. + * + * _Accepting payable debit notes during a long activity is considered a good practice in Golem Network._ + * The SDK will accept debit notes each 2 minutes by default. */ - debitNotesAcceptanceTimeoutSec?: number; + midAgreementDebitNoteIntervalSec?: number; /** * Maximum time to receive payment for any debit note. At the same time, the minimum interval between mid-agreement payments. diff --git a/src/market/factory.test.ts b/src/market/factory.test.ts index 38395be2d..ce1fa3fc2 100644 --- a/src/market/factory.test.ts +++ b/src/market/factory.test.ts @@ -45,6 +45,7 @@ describe("Demand Factory", () => { // The properties responsible for mid-agreements payments are set expect(demandRequestBody.properties["golem.com.payment.debit-notes.accept-timeout?"]).toBeDefined(); + expect(demandRequestBody.properties["golem.com.scheme.payu.debit-note.interval-sec?"]).toBeDefined(); expect(demandRequestBody.properties["golem.com.scheme.payu.payment-timeout-sec?"]).toBeDefined(); expect(demandRequestBody.properties["golem.srv.comp.expiration"]).toBeDefined(); diff --git a/src/market/factory.ts b/src/market/factory.ts index 6faf5841f..0fc0d0628 100644 --- a/src/market/factory.ts +++ b/src/market/factory.ts @@ -54,12 +54,13 @@ export class DemandFactory { .addProperty("golem.srv.caps.multi-activity", true) .addProperty("golem.srv.comp.expiration", Date.now() + this.options.expirationSec * 1000) .addProperty("golem.node.debug.subnet", this.options.subnetTag) + .addProperty("golem.com.payment.debit-notes.accept-timeout?", this.options.debitNotesAcceptanceTimeoutSec) .addConstraint("golem.com.pricing.model", "linear") .addConstraint("golem.node.debug.subnet", this.options.subnetTag); // Configure mid-agreement payments builder - .addProperty("golem.com.payment.debit-notes.accept-timeout?", this.options.debitNotesAcceptanceTimeoutSec) + .addProperty("golem.com.scheme.payu.debit-note.interval-sec?", this.options.midAgreementDebitNoteIntervalSec) .addProperty("golem.com.scheme.payu.payment-timeout-sec?", this.options.midAgreementPaymentTimeoutSec); return builder.getDecorations(); diff --git a/src/market/service.ts b/src/market/service.ts index 0e8b0dbed..278ad7148 100644 --- a/src/market/service.ts +++ b/src/market/service.ts @@ -125,14 +125,23 @@ export class MarketService { } private async isProposalValid(proposal: Proposal): Promise<{ result: boolean; reason?: string }> { - if (!this.allocation) throw new Error("The service has not been started correctly."); + if (!this.allocation) { + throw new Error("The service has not been started correctly."); + } + const timeout = proposal.properties["golem.com.payment.debit-notes.accept-timeout?"]; - if (timeout && timeout < this.options.debitNotesAcceptanceTimeoutSec) + if (timeout && timeout < this.options.debitNotesAcceptanceTimeoutSec) { return { result: false, reason: "Debit note acceptance timeout too short" }; - if (!proposal.hasPaymentPlatform(this.allocation.paymentPlatform)) + } + + if (!proposal.hasPaymentPlatform(this.allocation.paymentPlatform)) { return { result: false, reason: "No common payment platform" }; - if (!(await this.options.proposalFilter(proposal))) + } + + if (!(await this.options.proposalFilter(proposal))) { return { result: false, reason: "Proposal rejected by Proposal Filter" }; + } + return { result: true }; }