From 33b12b568cbde23d327b220f0ef386163b7077dc Mon Sep 17 00:00:00 2001 From: Henry Tsai Date: Thu, 11 Jan 2024 14:23:09 -0800 Subject: [PATCH] Exposed DWN_REGISTRATION_PROOF_OF_WORK_INITIAL_MAX_HASH setting --- README.md | 25 ++++++----- src/config.ts | 1 + src/dwn-server.ts | 1 + src/registration/proof-of-work-manager.ts | 45 ++++++++++--------- src/registration/registration-manager.ts | 5 ++- tests/dwn-server.spec.ts | 7 +-- tests/http-api.spec.ts | 4 +- .../proof-of-work-manager.spec.ts | 28 ++++++------ tests/scenarios/registration.spec.ts | 14 +++--- 9 files changed, 72 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 28d4f32..7bf861d 100644 --- a/README.md +++ b/README.md @@ -276,18 +276,19 @@ cloudflared tunnel --url http://localhost:3000 Configuration can be set using environment variables -| Env Var | Description | Default | -| ---------------------------------------- | --------------------------------------------------------------------------------------- | ---------------------- | -| `DS_PORT` | Port that the server listens on | `3000` | -| `DS_MAX_RECORD_DATA_SIZE` | Maximum size for `RecordsWrite` data. use `b`, `kb`, `mb`, `gb` for value | `1gb` | -| `DS_WEBSOCKET_SERVER` | Whether to enable listening over `ws:`. values: `on`,`off` | `on` | -| `DWN_REGISTRATION_STORE_URL` | URL to use for storage of registered DIDs | `sqlite://data/dwn.db` | -| `DWN_REGISTRATION_PROOF_OF_WORK_ENABLED` | Require new users to complete a proof-of-work challenge | `false` | -| `DWN_TERMS_OF_SERVICE_FILE_PATH` | Required terms of service agreement if set. Value is path to the terms of service file. | unset | -| `DWN_STORAGE` | URL to use for storage by default. See [Storage Options](#storage-options) for details | `level://data` | -| `DWN_STORAGE_MESSAGES` | URL to use for storage of messages. | value of `DWN_STORAGE` | -| `DWN_STORAGE_DATA` | URL to use for data storage | value of `DWN_STORAGE` | -| `DWN_STORAGE_EVENTS` | URL to use for event storage | value of `DWN_STORAGE` | +| Env Var | Description | Default | +| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------- | +| `DS_PORT` | Port that the server listens on | `3000` | +| `DS_MAX_RECORD_DATA_SIZE` | Maximum size for `RecordsWrite` data. use `b`, `kb`, `mb`, `gb` for value | `1gb` | +| `DS_WEBSOCKET_SERVER` | Whether to enable listening over `ws:`. values: `on`,`off` | `on` | +| `DWN_REGISTRATION_STORE_URL` | URL to use for storage of registered DIDs | `sqlite://data/dwn.db` | +| `DWN_REGISTRATION_PROOF_OF_WORK_ENABLED` | Require new users to complete a proof-of-work challenge | `false` | +| `DWN_REGISTRATION_PROOF_OF_WORK_INITIAL_MAX_HASH` | Initial maximum allowed hash in 64 char HEX string. The more leading zeros (smaller number) the higher the difficulty. | `false` | +| `DWN_TERMS_OF_SERVICE_FILE_PATH` | Required terms of service agreement if set. Value is path to the terms of service file. | unset | +| `DWN_STORAGE` | URL to use for storage by default. See [Storage Options](#storage-options) for details | `level://data` | +| `DWN_STORAGE_MESSAGES` | URL to use for storage of messages. | value of `DWN_STORAGE` | +| `DWN_STORAGE_DATA` | URL to use for data storage | value of `DWN_STORAGE` | +| `DWN_STORAGE_EVENTS` | URL to use for event storage | value of `DWN_STORAGE` | ### Storage Options diff --git a/src/config.ts b/src/config.ts index 0a3655a..44d71da 100644 --- a/src/config.ts +++ b/src/config.ts @@ -17,6 +17,7 @@ export const config = { // tenant registration feature configuration registrationStoreUrl: process.env.DWN_REGISTRATION_STORE_URL || process.env.DWN_STORAGE || 'sqlite://data/dwn.db', registrationProofOfWorkEnabled: process.env.DWN_REGISTRATION_PROOF_OF_WORK_ENABLED === 'true', + registrationProofOfWorkInitialMaxHash: process.env.DWN_REGISTRATION_PROOF_OF_WORK_INITIAL_MAX_HASH, termsOfServiceFilePath: process.env.DWN_TERMS_OF_SERVICE_FILE_PATH, // log level - trace/debug/info/warn/error diff --git a/src/dwn-server.ts b/src/dwn-server.ts index 65de5a5..8d55674 100644 --- a/src/dwn-server.ts +++ b/src/dwn-server.ts @@ -56,6 +56,7 @@ export class DwnServer { registrationManager = await RegistrationManager.create({ registrationStoreUrl: this.config.registrationStoreUrl, termsOfServiceFilePath: this.config.termsOfServiceFilePath, + initialMaximumAllowedHashValue: this.config.registrationProofOfWorkInitialMaxHash, }); this.dwn = await Dwn.create(getDWNConfig(this.config, registrationManager)); diff --git a/src/registration/proof-of-work-manager.ts b/src/registration/proof-of-work-manager.ts index 9969b22..c7fbed3 100644 --- a/src/registration/proof-of-work-manager.ts +++ b/src/registration/proof-of-work-manager.ts @@ -7,6 +7,9 @@ import { ProofOfWork } from "./proof-of-work.js"; * Can have multiple instances each having their own desired solve rate and difficulty. */ export class ProofOfWorkManager { + // Takes from seconds to ~1 minute to solve on an M1 MacBook. + private static readonly defaultMaximumAllowedHashValue = '000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'; + // Challenge nonces that can be used for proof-of-work. private challengeNonces: { currentChallengeNonce: string, previousChallengeNonce?: string }; @@ -14,8 +17,8 @@ export class ProofOfWorkManager { private proofOfWorkOfLastMinute: Map = new Map(); // proofOfWorkId -> timestamp of proof-of-work private difficultyIncreaseMultiplier: number; - private currentMaximumHashValueAsBigInt: bigint; - private initialMaximumHashValueAsBigInt: bigint; + private currentMaximumAllowedHashValueAsBigInt: bigint; + private initialMaximumAllowedHashValueAsBigInt: bigint; private desiredSolveCountPerMinute: number; /** @@ -32,7 +35,7 @@ export class ProofOfWorkManager { * The current maximum allowed hash value. */ public get currentMaximumAllowedHashValue(): bigint { - return this.currentMaximumHashValueAsBigInt; + return this.currentMaximumAllowedHashValueAsBigInt; } /** @@ -44,16 +47,16 @@ export class ProofOfWorkManager { private constructor (input: { desiredSolveCountPerMinute: number, - initialMaximumHashValue: string, + initialMaximumAllowedHashValue: string, difficultyIncreaseMultiplier: number, challengeRefreshFrequencyInSeconds: number, difficultyReevaluationFrequencyInSeconds: number }) { - const { desiredSolveCountPerMinute, initialMaximumHashValue } = input; + const { desiredSolveCountPerMinute, initialMaximumAllowedHashValue } = input; this.challengeNonces = { currentChallengeNonce: ProofOfWork.generateNonce() }; - this.currentMaximumHashValueAsBigInt = BigInt(`0x${initialMaximumHashValue}`); - this.initialMaximumHashValueAsBigInt = BigInt(`0x${initialMaximumHashValue}`); + this.currentMaximumAllowedHashValueAsBigInt = BigInt(`0x${initialMaximumAllowedHashValue}`); + this.initialMaximumAllowedHashValueAsBigInt = BigInt(`0x${initialMaximumAllowedHashValue}`); this.desiredSolveCountPerMinute = desiredSolveCountPerMinute; this.difficultyIncreaseMultiplier = input.difficultyIncreaseMultiplier; this.challengeRefreshFrequencyInSeconds = input.challengeRefreshFrequencyInSeconds; @@ -70,21 +73,22 @@ export class ProofOfWorkManager { */ public static async create(input: { desiredSolveCountPerMinute: number, - initialMaximumHashValue: string, autoStart: boolean, + initialMaximumAllowedHashValue?: string, difficultyIncreaseMultiplier?: number, challengeRefreshFrequencyInSeconds?: number, difficultyReevaluationFrequencyInSeconds?: number }): Promise { - const { desiredSolveCountPerMinute, initialMaximumHashValue } = input; + const { desiredSolveCountPerMinute } = input; + const initialMaximumAllowedHashValue = input.initialMaximumAllowedHashValue ?? ProofOfWorkManager.defaultMaximumAllowedHashValue; const difficultyIncreaseMultiplier = input.difficultyIncreaseMultiplier ?? 1; // 1x default const challengeRefreshFrequencyInSeconds = input.challengeRefreshFrequencyInSeconds ?? 10 * 60; // 10 minutes default const difficultyReevaluationFrequencyInSeconds = input.difficultyReevaluationFrequencyInSeconds ?? 10; // 10 seconds default const proofOfWorkManager = new ProofOfWorkManager({ desiredSolveCountPerMinute, - initialMaximumHashValue, + initialMaximumAllowedHashValue, difficultyIncreaseMultiplier, challengeRefreshFrequencyInSeconds, difficultyReevaluationFrequencyInSeconds @@ -218,42 +222,43 @@ export class ProofOfWorkManager { // if solve rate is higher than desired, make difficulty harder by making the max allowed hash value smaller const currentSolveRateInFractionOfDesiredSolveRate = latestSolveCountPerMinute / this.desiredSolveCountPerMinute; - const newMaximumHashValueAsBigIntPriorToMultiplierAdjustment - = (this.currentMaximumHashValueAsBigInt * BigInt(scaleFactor)) / + const newMaximumAllowedHashValueAsBigIntPriorToMultiplierAdjustment + = (this.currentMaximumAllowedHashValueAsBigInt * BigInt(scaleFactor)) / (BigInt(Math.floor(currentSolveRateInFractionOfDesiredSolveRate * this.difficultyIncreaseMultiplier * scaleFactor))); const hashValueDecreaseAmountPriorToEvaluationFrequencyAdjustment - = (this.currentMaximumHashValueAsBigInt - newMaximumHashValueAsBigIntPriorToMultiplierAdjustment) * + = (this.currentMaximumAllowedHashValueAsBigInt - newMaximumAllowedHashValueAsBigIntPriorToMultiplierAdjustment) * (BigInt(Math.floor(this.difficultyIncreaseMultiplier * scaleFactor)) / BigInt(scaleFactor)); // Adjustment based on the reevaluation frequency to provide more-or-less consistent behavior regardless of the reevaluation frequency. const hashValueDecreaseAmount = hashValueDecreaseAmountPriorToEvaluationFrequencyAdjustment / BigInt(difficultyEvaluationsPerMinute); - this.currentMaximumHashValueAsBigInt -= hashValueDecreaseAmount; + this.currentMaximumAllowedHashValueAsBigInt -= hashValueDecreaseAmount; // Resetting to allow hash increment to be recalculated when difficulty needs to be reduced (in `else` block below) this.hashValueIncrementPerEvaluation = undefined; } else { // if solve rate is lower than desired, make difficulty easier by making the max allowed hash value larger - if (this.currentMaximumHashValueAsBigInt === this.initialMaximumHashValueAsBigInt) { + if (this.currentMaximumAllowedHashValueAsBigInt === this.initialMaximumAllowedHashValueAsBigInt) { // if current difficulty is already at initial difficulty, nothing to do return; } if (this.hashValueIncrementPerEvaluation === undefined) { const backToInitialDifficultyInMinutes = 10; - const differenceBetweenInitialAndCurrentDifficulty = this.initialMaximumHashValueAsBigInt - this.currentMaximumHashValueAsBigInt; + const differenceBetweenInitialAndCurrentDifficulty + = this.initialMaximumAllowedHashValueAsBigInt - this.currentMaximumAllowedHashValueAsBigInt; this.hashValueIncrementPerEvaluation = differenceBetweenInitialAndCurrentDifficulty / BigInt(backToInitialDifficultyInMinutes * difficultyEvaluationsPerMinute); } // if newly calculated difficulty is lower than initial difficulty, just use the initial difficulty - const newMaximumAllowedHashValueAsBigInt = this.currentMaximumHashValueAsBigInt + this.hashValueIncrementPerEvaluation; - if (newMaximumAllowedHashValueAsBigInt >= this.initialMaximumHashValueAsBigInt) { - this.currentMaximumHashValueAsBigInt = this.initialMaximumHashValueAsBigInt; + const newMaximumAllowedHashValueAsBigInt = this.currentMaximumAllowedHashValueAsBigInt + this.hashValueIncrementPerEvaluation; + if (newMaximumAllowedHashValueAsBigInt >= this.initialMaximumAllowedHashValueAsBigInt) { + this.currentMaximumAllowedHashValueAsBigInt = this.initialMaximumAllowedHashValueAsBigInt; } else { - this.currentMaximumHashValueAsBigInt = newMaximumAllowedHashValueAsBigInt; + this.currentMaximumAllowedHashValueAsBigInt = newMaximumAllowedHashValueAsBigInt; } } } diff --git a/src/registration/registration-manager.ts b/src/registration/registration-manager.ts index 19662c0..ad7e893 100644 --- a/src/registration/registration-manager.ts +++ b/src/registration/registration-manager.ts @@ -54,8 +54,9 @@ export class RegistrationManager implements TenantGate { public static async create(input: { registrationStoreUrl: string, termsOfServiceFilePath?: string + initialMaximumAllowedHashValue?: string, }): Promise { - const { termsOfServiceFilePath, registrationStoreUrl } = input; + const { termsOfServiceFilePath, registrationStoreUrl, initialMaximumAllowedHashValue } = input; const registrationManager = new RegistrationManager(termsOfServiceFilePath); @@ -63,7 +64,7 @@ export class RegistrationManager implements TenantGate { registrationManager.proofOfWorkManager = await ProofOfWorkManager.create({ autoStart: true, desiredSolveCountPerMinute: 10, - initialMaximumHashValue: '00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' + initialMaximumAllowedHashValue, }); // Initialize RegistrationStore. diff --git a/tests/dwn-server.spec.ts b/tests/dwn-server.spec.ts index b3e5e7a..ab00f4e 100644 --- a/tests/dwn-server.spec.ts +++ b/tests/dwn-server.spec.ts @@ -2,17 +2,17 @@ import { expect } from 'chai'; import { config } from '../src/config.js'; import { DwnServer } from '../src/dwn-server.js'; -import { getTestDwn } from './test-dwn.js'; describe('DwnServer', function () { let dwnServer: DwnServer; before(async function () { - const testDwn = await getTestDwn(); - dwnServer = new DwnServer({ dwn: testDwn, config: config }); + dwnServer = new DwnServer({ config: config }); }); + after(async function () { dwnServer.stop(() => console.log('server stop')); }); + it('should create an instance of DwnServer', function () { expect(dwnServer).to.be.an.instanceOf(DwnServer); }); @@ -24,6 +24,7 @@ describe('DwnServer', function () { }); expect(response.status).to.equal(200); }); + it('should stop the server', async function () { dwnServer.stop(() => console.log('server Stop')); // Add an assertion to check that the server has been stopped diff --git a/tests/http-api.spec.ts b/tests/http-api.spec.ts index 0afeaa4..b946d0d 100644 --- a/tests/http-api.spec.ts +++ b/tests/http-api.spec.ts @@ -54,11 +54,13 @@ describe('http api', function () { config.registrationStoreUrl = 'sqlite://'; config.registrationProofOfWorkEnabled = true; config.termsOfServiceFilePath = './tests/fixtures/terms-of-service.txt'; + config.registrationProofOfWorkInitialMaxHash = '0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'; // 1 in 16 chance of solving // RegistrationManager creation const registrationStoreUrl = config.registrationStoreUrl; const termsOfServiceFilePath = config.termsOfServiceFilePath; - registrationManager = await RegistrationManager.create({ registrationStoreUrl, termsOfServiceFilePath }); + const initialMaximumAllowedHashValue = config.registrationProofOfWorkInitialMaxHash; + registrationManager = await RegistrationManager.create({ registrationStoreUrl, termsOfServiceFilePath, initialMaximumAllowedHashValue }); dwn = await getTestDwn(registrationManager); diff --git a/tests/registration/proof-of-work-manager.spec.ts b/tests/registration/proof-of-work-manager.spec.ts index 081c04f..58fd481 100644 --- a/tests/registration/proof-of-work-manager.spec.ts +++ b/tests/registration/proof-of-work-manager.spec.ts @@ -26,11 +26,11 @@ describe('ProofOfWorkManager', function () { it('should periodically refresh the challenge nonce and proof-of-work difficulty', async function () { const desiredSolveCountPerMinute = 10; - const initialMaximumHashValue = 'FFFFFFFF'; + const initialMaximumAllowedHashValue = 'FFFFFFFF'; const proofOfWorkManager = await ProofOfWorkManager.create({ autoStart: true, desiredSolveCountPerMinute, - initialMaximumHashValue, + initialMaximumAllowedHashValue, }); // stub that throws half the time @@ -62,11 +62,11 @@ describe('ProofOfWorkManager', function () { it('should increase difficulty if proof-of-work rate goes above desired rate and reduce difficulty as proof-of-work rate falls below desired rate.', async function () { const desiredSolveCountPerMinute = 10; - const initialMaximumHashValue = 'FFFFFFFF'; + const initialMaximumAllowedHashValue = 'FFFFFFFF'; const proofOfWorkManager = await ProofOfWorkManager.create({ autoStart: true, desiredSolveCountPerMinute, - initialMaximumHashValue, + initialMaximumAllowedHashValue, }); // Load up desiredSolveRatePerMinute number of proof-of-work entries, so all future new entries will increase the complexity. @@ -74,8 +74,8 @@ describe('ProofOfWorkManager', function () { await proofOfWorkManager.recordProofOfWork(uuidv4()); } - let initialMaximumAllowedHashValue = proofOfWorkManager.currentMaximumAllowedHashValue; - let lastMaximumAllowedHashValue = BigInt('0x' + initialMaximumHashValue); + let baselineMaximumAllowedHashValue = proofOfWorkManager.currentMaximumAllowedHashValue; + let lastMaximumAllowedHashValue = BigInt('0x' + initialMaximumAllowedHashValue); const lastSolveCountPerMinute = 0; for (let i = 0; i < 100; i++) { // Simulating 1 proof-of-work per second which for 100 seconds. @@ -87,7 +87,7 @@ describe('ProofOfWorkManager', function () { expect(proofOfWorkManager.currentMaximumAllowedHashValue <= lastMaximumAllowedHashValue).to.be.true; lastMaximumAllowedHashValue = proofOfWorkManager.currentMaximumAllowedHashValue; } - expect(proofOfWorkManager.currentMaximumAllowedHashValue < initialMaximumAllowedHashValue).to.be.true; + expect(proofOfWorkManager.currentMaximumAllowedHashValue < baselineMaximumAllowedHashValue).to.be.true; // Simulated 100 seconds has passed, so all proof-of-work entries should be removed. clock.tick(100_000); @@ -95,7 +95,7 @@ describe('ProofOfWorkManager', function () { expect(proofOfWorkManager.currentSolveCountPerMinute).to.equal(0); - initialMaximumAllowedHashValue = proofOfWorkManager.currentMaximumAllowedHashValue; + baselineMaximumAllowedHashValue = proofOfWorkManager.currentMaximumAllowedHashValue; for (let i = 0; i < 100; i++) { // Simulating no proof-of-work load for 100 seconds. clock.tick(1000); @@ -104,17 +104,17 @@ describe('ProofOfWorkManager', function () { expect(proofOfWorkManager.currentMaximumAllowedHashValue >= lastMaximumAllowedHashValue).to.be.true; lastMaximumAllowedHashValue = proofOfWorkManager.currentMaximumAllowedHashValue; } - expect(proofOfWorkManager.currentMaximumAllowedHashValue > initialMaximumAllowedHashValue).to.be.true; + expect(proofOfWorkManager.currentMaximumAllowedHashValue > baselineMaximumAllowedHashValue).to.be.true; }); it('should reduce difficulty back to initial difficulty when proof-of-work rate is lower than desired rate for long enough', async function () { const desiredSolveCountPerMinute = 10; - const initialMaximumHashValue = 'FFFFFFFF'; - const initialMaximumHashValueAsBigInt = BigInt('0x' + initialMaximumHashValue); + const initialMaximumAllowedHashValue = 'FFFFFFFF'; + const initialMaximumAllowedHashValueAsBigInt = BigInt('0x' + initialMaximumAllowedHashValue); const proofOfWorkManager = await ProofOfWorkManager.create({ autoStart: true, desiredSolveCountPerMinute, - initialMaximumHashValue, + initialMaximumAllowedHashValue, }); // Load up desiredSolveRatePerMinute number of proof-of-work entries, so all future new entries will increase the complexity. @@ -127,12 +127,12 @@ describe('ProofOfWorkManager', function () { await proofOfWorkManager.recordProofOfWork(uuidv4()); clock.tick(1000); } - expect(proofOfWorkManager.currentMaximumAllowedHashValue < initialMaximumHashValueAsBigInt).to.be.true; + expect(proofOfWorkManager.currentMaximumAllowedHashValue < initialMaximumAllowedHashValueAsBigInt).to.be.true; // Simulated 1 hour has passed. clock.tick(60 * 60 * 1000); clock.runToLast(); - expect(proofOfWorkManager.currentMaximumAllowedHashValue === initialMaximumHashValueAsBigInt).to.be.true; + expect(proofOfWorkManager.currentMaximumAllowedHashValue === initialMaximumAllowedHashValueAsBigInt).to.be.true; }); }); diff --git a/tests/scenarios/registration.spec.ts b/tests/scenarios/registration.spec.ts index e1d7aef..66ac17e 100644 --- a/tests/scenarios/registration.spec.ts +++ b/tests/scenarios/registration.spec.ts @@ -57,11 +57,13 @@ describe('Registration scenarios', function () { config.registrationStoreUrl = 'sqlite://'; config.registrationProofOfWorkEnabled = true; config.termsOfServiceFilePath = './tests/fixtures/terms-of-service.txt'; + config.registrationProofOfWorkInitialMaxHash = '0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'; // 1 in 16 chance of solving // RegistrationManager creation const registrationStoreUrl = config.registrationStoreUrl; const termsOfServiceFilePath = config.termsOfServiceFilePath; - registrationManager = await RegistrationManager.create({ registrationStoreUrl, termsOfServiceFilePath }); + const initialMaximumAllowedHashValue = config.registrationProofOfWorkInitialMaxHash; + registrationManager = await RegistrationManager.create({ registrationStoreUrl, termsOfServiceFilePath, initialMaximumAllowedHashValue }); dwn = await getTestDwn(registrationManager); @@ -179,8 +181,8 @@ describe('Registration scenarios', function () { const { challengeNonce } = registrationManager.getProofOfWorkChallenge(); // Force the difficulty to be practically impossible. - const originalMaximumAllowedHashValueAsBigInt = registrationManager['proofOfWorkManager']['currentMaximumHashValueAsBigInt']; // for restoring later below - registrationManager['proofOfWorkManager']['currentMaximumHashValueAsBigInt'] = BigInt('0x0000000000000000000000000000000000000000000000000000000000000001'); + const originalMaximumAllowedHashValueAsBigInt = registrationManager['proofOfWorkManager']['currentMaximumAllowedHashValueAsBigInt']; // for restoring later below + registrationManager['proofOfWorkManager']['currentMaximumAllowedHashValueAsBigInt'] = BigInt('0x0000000000000000000000000000000000000000000000000000000000000001'); const registrationData: RegistrationData = { did: alice.did, @@ -194,9 +196,6 @@ describe('Registration scenarios', function () { requestData: JSON.stringify(registrationData), }); - // Restoring original difficulty for subsequent tests. - registrationManager['proofOfWorkManager']['currentMaximumHashValueAsBigInt'] = originalMaximumAllowedHashValueAsBigInt; - // 2. Alice sends the registration request to the server and is rejected. const registrationRequest: RegistrationRequest = { registrationData, @@ -214,6 +213,9 @@ describe('Registration scenarios', function () { const registrationResponseBody = await registrationResponse.json() as any; expect(registrationResponse.status).to.equal(400); expect(registrationResponseBody.code).to.equal(DwnServerErrorCode.ProofOfWorkInsufficientSolutionNonce); + + // Restoring original difficulty for subsequent tests. + registrationManager['proofOfWorkManager']['currentMaximumAllowedHashValueAsBigInt'] = originalMaximumAllowedHashValueAsBigInt; }); it('should reject a registration request that uses an invalid/outdated terms-of-service hash', async () => {