diff --git a/lib/bitcoin/BitcoinClient.ts b/lib/bitcoin/BitcoinClient.ts index d9108b746..a6b9c6f3c 100644 --- a/lib/bitcoin/BitcoinClient.ts +++ b/lib/bitcoin/BitcoinClient.ts @@ -7,9 +7,9 @@ import BitcoinOutputModel from './models/BitcoinOutputModel'; import BitcoinTransactionModel from './models/BitcoinTransactionModel'; import BitcoinWallet from './BitcoinWallet'; import IBitcoinWallet from './interfaces/IBitcoinWallet'; -import nodeFetch, { FetchError, Response, RequestInit } from 'node-fetch'; +import nodeFetch, { FetchError, RequestInit, Response } from 'node-fetch'; import ReadableStream from '../common/ReadableStream'; -import { Address, crypto, Networks, PrivateKey, Script, Transaction, Unit, Block } from 'bitcore-lib'; +import { Address, Block, crypto, Networks, PrivateKey, Script, Transaction, Unit } from 'bitcore-lib'; import { IBlockInfo } from './BitcoinProcessor'; /** diff --git a/lib/core/versions/0.11.0/MongoDbOperationQueue.ts b/lib/core/versions/0.11.0/MongoDbOperationQueue.ts index 607aa5eb5..2e94a84a1 100644 --- a/lib/core/versions/0.11.0/MongoDbOperationQueue.ts +++ b/lib/core/versions/0.11.0/MongoDbOperationQueue.ts @@ -1,7 +1,7 @@ import ErrorCode from './ErrorCode'; import IOperationQueue from './interfaces/IOperationQueue'; import SidetreeError from '../../../common/SidetreeError'; -import { Binary, Collection, MongoClient, Db } from 'mongodb'; +import { Binary, Collection, Db, MongoClient } from 'mongodb'; import QueuedOperationModel from './models/QueuedOperationModel'; /** diff --git a/lib/core/versions/latest/CreateOperation.ts b/lib/core/versions/latest/CreateOperation.ts index 432a52186..a10234f94 100644 --- a/lib/core/versions/latest/CreateOperation.ts +++ b/lib/core/versions/latest/CreateOperation.ts @@ -2,12 +2,12 @@ import DeltaModel from './models/DeltaModel'; import Encoder from './Encoder'; import ErrorCode from './ErrorCode'; import JsonAsync from './util/JsonAsync'; +import JsonCanonicalizer from './util/JsonCanonicalizer'; import Multihash from './Multihash'; import Operation from './Operation'; import OperationModel from './models/OperationModel'; import OperationType from '../../enums/OperationType'; import SidetreeError from '../../../common/SidetreeError'; -import JsonCanonicalizer from './util/JsonCanonicalizer'; interface SuffixDataModel { deltaHash: string; @@ -99,6 +99,7 @@ export default class CreateOperation implements OperationModel { const operationObject = await JsonAsync.parse(operationJsonString); let createOperation; if (typeof operationObject.suffix_data === 'string') { + // TODO: SIP 2 #781 deprecates this. Should be deleted when fully switched over createOperation = await CreateOperation.parseObject(operationObject, operationBuffer, false); } else { createOperation = CreateOperation.parseJcsObject(operationObject, operationBuffer); @@ -123,11 +124,15 @@ export default class CreateOperation implements OperationModel { } CreateOperation.validateSuffixData(operationObject.suffix_data); - const suffixData = { + const suffixData: SuffixDataModel = { deltaHash: operationObject.suffix_data.delta_hash, recoveryCommitment: operationObject.suffix_data.recovery_commitment }; + if (operationObject.suffix_data.type !== undefined) { + suffixData.type = operationObject.suffix_data.type + } + // For compatibility with data pruning, we have to assume that `delta` may be unavailable, // thus an operation with invalid `delta` needs to be processed as an operation with unavailable `delta`, // so here we let `delta` be `undefined`. @@ -157,7 +162,7 @@ export default class CreateOperation implements OperationModel { * @param anchorFileMode If set to true, then `delta` and `type` properties are expected to be absent. */ public static async parseObject (operationObject: any, operationBuffer: Buffer, anchorFileMode: boolean): Promise { - // TODO SIP 2 #781 deprecates this. Should be deleted when fully switched over + // TODO: SIP 2 #781 deprecates this. Should be deleted when fully switched over let expectedPropertyCount = 3; if (anchorFileMode) { expectedPropertyCount = 1; diff --git a/lib/core/versions/latest/Did.ts b/lib/core/versions/latest/Did.ts index 099a0017b..5ffd8734f 100644 --- a/lib/core/versions/latest/Did.ts +++ b/lib/core/versions/latest/Did.ts @@ -1,12 +1,12 @@ import CreateOperation from './CreateOperation'; import Delta from './Delta'; +import Encoder from './Encoder'; import ErrorCode from './ErrorCode'; +import JsonCanonicalizer from './util/JsonCanonicalizer'; import Multihash from './Multihash'; import OperationType from '../../enums/OperationType'; import SidetreeError from '../../../common/SidetreeError'; import { URL } from 'url'; -import Encoder from './Encoder'; -import JsonCanonicalizer from './util/JsonCanonicalizer'; /** * Class containing reusable Sidetree DID related operations. @@ -45,8 +45,8 @@ export default class Did { const didWithoutPrefix = did.split(didPrefix)[1]; - // split by : and ?, if there are 1 elements, then it's short form. Long form has 2 elements - // when the ? format is deprecated, `:` will be the only seperator. + // split by : and ?, if there is 1 element, then it's short form. Long form has 2 elements + // TODO: SIP 2 #781 when the ? format is deprecated, `:` will be the only seperator. const didSplitLength = didWithoutPrefix.split(/:|\?/).length; if (didSplitLength === 1) { this.isShortForm = true; @@ -174,7 +174,7 @@ export default class Did { try { initialStateObject = JSON.parse(initialStateDecodedJcs); } catch { - throw new SidetreeError(ErrorCode.DidInitialStateJcsIsNotJosn, 'long form initial state should be encoded jcs'); + throw new SidetreeError(ErrorCode.DidInitialStateJcsIsNotJosn, 'Long form initial state should be encoded jcs.'); } Did.validateInitialState(initialStateEncodedJcs, initialStateObject); @@ -195,12 +195,12 @@ export default class Did { private static validateInitialState (initialStateEncodedJcs: string, initialStateObject: any): void { const expectedInitialState = Encoder.encode(JsonCanonicalizer.canonicalizeAsBuffer(initialStateObject)); if (expectedInitialState !== initialStateEncodedJcs) { - throw new SidetreeError(ErrorCode.DidInitialStateJcsIsNotJcs, 'make sure to jcs then encode the initial state'); + throw new SidetreeError(ErrorCode.DidInitialStateJcsIsNotJcs, 'Initial state object and JCS string mismatch.'); } } private static async constructCreateOperationFromInitialState (initialState: string): Promise { - // TODO SIP 2 #781 deprecates this. Should be deleted when fully switched over + // TODO: SIP 2 #781 deprecates this. Should be deleted when fully switched over // Initial state should be in the format: . const firstIndexOfDot = initialState.indexOf('.'); if (firstIndexOfDot === -1) { diff --git a/lib/core/versions/latest/MongoDbOperationQueue.ts b/lib/core/versions/latest/MongoDbOperationQueue.ts index 607aa5eb5..2e94a84a1 100644 --- a/lib/core/versions/latest/MongoDbOperationQueue.ts +++ b/lib/core/versions/latest/MongoDbOperationQueue.ts @@ -1,7 +1,7 @@ import ErrorCode from './ErrorCode'; import IOperationQueue from './interfaces/IOperationQueue'; import SidetreeError from '../../../common/SidetreeError'; -import { Binary, Collection, MongoClient, Db } from 'mongodb'; +import { Binary, Collection, Db, MongoClient } from 'mongodb'; import QueuedOperationModel from './models/QueuedOperationModel'; /** diff --git a/tests/core/CreateOperation.spec.ts b/tests/core/CreateOperation.spec.ts index 868b0ed49..4bba2a05b 100644 --- a/tests/core/CreateOperation.spec.ts +++ b/tests/core/CreateOperation.spec.ts @@ -7,6 +7,9 @@ import OperationGenerator from '../generators/OperationGenerator'; import OperationType from '../../lib/core/enums/OperationType'; import SidetreeError from '../../lib/common/SidetreeError'; +import * as fs from 'fs'; +import * as suffixData from '../fixtures/uniqueSuffix/suffixData.json'; + describe('CreateOperation', async () => { describe('parseJcsObject', () => { it('should leave delta as empty if it is not valid', () => { @@ -56,8 +59,17 @@ describe('CreateOperation', async () => { } }); }); + + describe('computeJcsDidUniqueSuffix', () => { + it('should return expected did unique suffix', () => { + const actual = Multihash.canonicalizeThenHashThenEncode(suffixData); + const expected = fs.readFileSync('tests/fixtures/uniqueSuffix/resultingSuffix.txt', 'utf8'); + expect(actual).toEqual(expected); + }) + }) + describe('computeDidUniqueSuffix()', async () => { - it('should pass test vector.', async (done) => { + it('should return expected did unique suffix', async (done) => { const suffixDataString = 'AStringActingAsTheSuffixData'; const encodedSuffixDataString = Encoder.encode(suffixDataString); const didUniqueSuffix = (CreateOperation as any).computeDidUniqueSuffix(encodedSuffixDataString); @@ -116,7 +128,7 @@ describe('CreateOperation', async () => { }); describe('parseSuffixData()', async () => { - // TODO SIP 2 #781 deprecates this. These tests can be siwtched over to validateSuffixData + // TODO: SIP 2 #781 deprecates this. These tests can be siwtched over to validateSuffixData it('should function as expected with type', async () => { const suffixData = { delta_hash: Encoder.encode(Multihash.hash(Buffer.from('some data'))), diff --git a/tests/fixtures/uniqueSuffix/resultingSuffix.txt b/tests/fixtures/uniqueSuffix/resultingSuffix.txt new file mode 100644 index 000000000..c2ac8597b --- /dev/null +++ b/tests/fixtures/uniqueSuffix/resultingSuffix.txt @@ -0,0 +1 @@ +EiDMM0OSF_J1SyCRFj-NtsyuXLP1HoFl-77QejaEwMW-kA \ No newline at end of file diff --git a/tests/fixtures/uniqueSuffix/suffixData.json b/tests/fixtures/uniqueSuffix/suffixData.json new file mode 100644 index 000000000..a5bb36887 --- /dev/null +++ b/tests/fixtures/uniqueSuffix/suffixData.json @@ -0,0 +1,4 @@ +{ + "delta_hash": "EiDv_M8oOqyYyWtvqAGG8CpXJlKXP4Q5D4H0zE55-PQqGw", + "recovery_commitment": "EiAL35tvU7ge-hZm2cBRG5IrY2St2NSXUar-H8RYBMKSCg" +} \ No newline at end of file diff --git a/tests/generators/OperationGenerator.ts b/tests/generators/OperationGenerator.ts index bd0a9ed58..77eaaf8c0 100644 --- a/tests/generators/OperationGenerator.ts +++ b/tests/generators/OperationGenerator.ts @@ -156,10 +156,11 @@ export default class OperationGenerator { recovery_commitment: Multihash.canonicalizeThenDoubleHashThenEncode(recoveryPublicKey) }; + console.log(suffixData); + const didUniqueSuffix = CreateOperation['computeJcsDidUniqueSuffix'](suffixData); const shortFormDid = `did:sidetree:${didUniqueSuffix}`; - // TODO: discuss if canonicalization is necessary. const initialState = { suffix_data: suffixData, delta: delta @@ -173,7 +174,6 @@ export default class OperationGenerator { longFormDid, shortFormDid, didUniqueSuffix - }; } diff --git a/tslint.json b/tslint.json index d70f274ca..4baf90602 100644 --- a/tslint.json +++ b/tslint.json @@ -42,6 +42,13 @@ "only-arrow-functions": [ true, "allow-named-functions" + ], + "ordered-imports": [ + true, + { + "import-sources-order": "any", + "named-imports-order": "case-insensitive" + } ] } } \ No newline at end of file