diff --git a/node/package.json b/node/package.json index df0b20a6a..cb3db0651 100644 --- a/node/package.json +++ b/node/package.json @@ -24,7 +24,7 @@ "compile": "tsc", "copy-non-ts-source": "rsync -rv --prune-empty-dirs --include='*.d.ts' --exclude='*.ts' src/ dist", "generate-apidoc": "typedoc", - "lint": "eslint . --ext .ts", + "lint": "eslint . --ext .ts --fix", "test": "jest" }, "license": "Apache-2.0", diff --git a/node/src/gateway.ts b/node/src/gateway.ts index f39f34480..7e286bb26 100644 --- a/node/src/gateway.ts +++ b/node/src/gateway.ts @@ -156,6 +156,13 @@ export interface Gateway { */ newSignedProposal(bytes: Uint8Array, signature: Uint8Array): Proposal; + /** + * Create a proposal with default signing implementation. + * @param bytes - Serialized proposal. + * @returns A signed proposal. + */ + newUnsignedProposal(bytes: Uint8Array): Proposal; + /** * Create a transaction with the specified digital signature. Supports off-line signing flow. * @param bytes - Serialized proposal. @@ -164,6 +171,13 @@ export interface Gateway { */ newSignedTransaction(bytes: Uint8Array, signature: Uint8Array): Transaction; + /** + * Create a transaction with the default signing implementation. + * @param bytes - Serialized proposal. + * @returns A signed transaction. + */ + newUnsignedTransaction(bytes: Uint8Array): Transaction; + /** * Create a commit with the specified digital signature, which can be used to access information about a * transaction that is committed to the ledger. Supports off-line signing flow. @@ -173,6 +187,14 @@ export interface Gateway { */ newSignedCommit(bytes: Uint8Array, signature: Uint8Array): Commit; + /** + * Create a commit with the dafault signing implementation, which can be used to access information about a + * transaction that is committed to the ledger. + * @param bytes - Serialized commit status request. + * @returns A signed commit status request. + */ + newUnsignedCommit(bytes: Uint8Array): Commit; + /** * Create a chaincode events request with the specified digital signature. Supports off-line signing flow. * @param bytes - Serialized chaincode events request. @@ -252,6 +274,14 @@ class GatewayImpl { return result; } + newUnsignedProposal(bytes: Uint8Array): Proposal { + return this.newSignedProposal(bytes, new Uint8Array()); + } + + newUnsignedTransaction(bytes: Uint8Array): Transaction { + return this.newSignedTransaction(bytes, new Uint8Array()); + } + newSignedTransaction(bytes: Uint8Array, signature: Uint8Array): Transaction { const preparedTransaction = gateway.PreparedTransaction.deserializeBinary(bytes); @@ -265,6 +295,10 @@ class GatewayImpl { return result; } + newUnsignedCommit(bytes: Uint8Array): Commit { + return this.newSignedCommit(bytes, new Uint8Array()); + } + newSignedCommit(bytes: Uint8Array, signature: Uint8Array): Commit { const signedRequest = gateway.SignedCommitStatusRequest.deserializeBinary(bytes); const request = gateway.CommitStatusRequest.deserializeBinary(signedRequest.getRequest_asU8()); diff --git a/node/src/offlinesign.test.ts b/node/src/offlinesign.test.ts index 87f8e930b..a3d69bdbe 100644 --- a/node/src/offlinesign.test.ts +++ b/node/src/offlinesign.test.ts @@ -283,6 +283,16 @@ describe('Offline sign', () => { expect(actual).toEqual(expected); }); + it('proposal keeps same digest using newUnsignedProposal', () => { + const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); + const expected = unsignedProposal.getDigest(); + + const signedProposal = gateway.newUnsignedProposal(unsignedProposal.getBytes()); + const actual = signedProposal.getDigest(); + + expect(actual).toEqual(expected); + }); + it('transaction keeps same digest', async () => { const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); const signedProposal = gateway.newSignedProposal(unsignedProposal.getBytes(), Buffer.from('SIGNATURE')); @@ -295,6 +305,18 @@ describe('Offline sign', () => { expect(actual).toEqual(expected); }); + it('transaction keeps same digest using newUnsignedTransaction', async () => { + const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); + const signedProposal = gateway.newUnsignedProposal(unsignedProposal.getBytes()); + const unsignedTransaction = await signedProposal.endorse(); + const expected = unsignedTransaction.getDigest(); + + const signedTransaction = gateway.newUnsignedTransaction(unsignedTransaction.getBytes()); + const actual = signedTransaction.getDigest(); + + expect(actual).toEqual(expected); + }); + it('transaction keeps same transaction ID', async () => { const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); const signedProposal = gateway.newSignedProposal(unsignedProposal.getBytes(), Buffer.from('SIGNATURE')); @@ -335,6 +357,20 @@ describe('Offline sign', () => { expect(actual).toEqual(expected); }); + it('commit keeps same digest using newUnsignedCommit', async () => { + const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); + const signedProposal = gateway.newUnsignedProposal(unsignedProposal.getBytes()); + const unsignedTransaction = await signedProposal.endorse(); + const signedTransaction = gateway.newUnsignedTransaction(unsignedTransaction.getBytes()); + const unsignedCommit = await signedTransaction.submit(); + const expected = unsignedCommit.getDigest(); + + const signedCommit = gateway.newUnsignedCommit(unsignedCommit.getBytes()); + const actual = signedCommit.getDigest(); + + expect(actual).toEqual(expected); + }); + it('chaincode events request keeps same digest', () => { const unsignedRequest = network.newChaincodeEventsRequest('CHAINCODE_NAME'); const expected = unsignedRequest.getDigest(); diff --git a/node/src/proposal.test.ts b/node/src/proposal.test.ts index d8bb4f9b8..1ea0ba3f9 100644 --- a/node/src/proposal.test.ts +++ b/node/src/proposal.test.ts @@ -250,6 +250,17 @@ describe('Proposal', () => { expect(signature).toBe('MY_SIGNATURE'); }); + it('uses signer for unsigned proposal', async () => { + signer.mockResolvedValue(Buffer.from('MY_SIGNATURE')); + const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); + const signedProposal = gateway.newUnsignedProposal(unsignedProposal.getBytes()); + await signedProposal.evaluate(); + + const evaluateRequest = client.getEvaluateRequests()[0]; + const signature = Buffer.from(evaluateRequest.getProposedTransaction()?.getSignature_asU8() ?? '').toString(); + expect(signature).toBe('MY_SIGNATURE'); + }); + it('uses hash', async () => { hash.mockReturnValue(Buffer.from('MY_DIGEST')); diff --git a/node/src/transaction.test.ts b/node/src/transaction.test.ts index 85e2c7679..d992b959b 100644 --- a/node/src/transaction.test.ts +++ b/node/src/transaction.test.ts @@ -158,6 +158,20 @@ describe('Transaction', () => { expect(signature).toBe('MY_SIGNATURE'); }); + it('uses signer for unsigned transaction submit', async () => { + signer.mockResolvedValue(Buffer.from('MY_SIGNATURE')); + + const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); + const signedProposal = gateway.newUnsignedProposal(unsignedProposal.getBytes()); + const unsignedTransaction = await signedProposal.endorse(); + + const signedTransaction = gateway.newUnsignedTransaction(unsignedTransaction.getBytes()); + await signedTransaction.submit(); + const submitRequest = client.getSubmitRequests()[0]; + const signature = Buffer.from(submitRequest.getPreparedTransaction()?.getSignature_asU8() ?? '').toString(); + expect(signature).toBe('MY_SIGNATURE'); + }); + it('uses signer for commit', async () => { signer.mockResolvedValue(Buffer.from('MY_SIGNATURE')); @@ -168,6 +182,23 @@ describe('Transaction', () => { expect(signature).toBe('MY_SIGNATURE'); }); + it('uses signer for unsigned commit', async () => { + signer.mockResolvedValue(Buffer.from('MY_SIGNATURE')); + + const unsignedProposal = contract.newProposal('TRANSACTION_NAME'); + const signedProposal = gateway.newUnsignedProposal(unsignedProposal.getBytes()); + const unsignedTransaction = await signedProposal.endorse(); + + const signedTransaction = gateway.newUnsignedTransaction(unsignedTransaction.getBytes()); + const unsignedCommit = await signedTransaction.submit(); + + gateway.newUnsignedCommit(unsignedCommit.getBytes()); + + const statusRequest = client.getCommitStatusRequests()[0]; + const signature = Buffer.from(statusRequest.getSignature() ?? '').toString(); + expect(signature).toBe('MY_SIGNATURE'); + }); + it('uses hash', async () => { hash.mockReturnValue(Buffer.from('MY_DIGEST'));