Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Commit

Permalink
feat!: convenient broadcast errors (#266)
Browse files Browse the repository at this point in the history
Co-authored-by: Konstantin Shuplenkov <konstantin.shuplenkov@dash.org>
  • Loading branch information
2 people authored and antouhou committed Oct 25, 2021
1 parent 35202b9 commit c58f3cf
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 185 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
DRIVE_BRANCH=feat/grpc-error-codes
DAPI_BRANCH=error-codes
DASHMATE_BRANCH=error-codes
TEST_SUITE_BRANCH=error-codes
DRIVE_BRANCH=bring-back-drive-errors
DAPI_BRANCH=send-metadata-buffer
DASHMATE_BRANCH=convenient-errors
TEST_SUITE_BRANCH=convenient-errors
219 changes: 102 additions & 117 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@
},
"homepage": "https://github.com/dashevo/DashJS#readme",
"dependencies": {
"@dashevo/dapi-client": "~0.21.0-dev.7",
"@dashevo/dapi-client": "~0.21.0-dev.9",
"@dashevo/dashcore-lib": "~0.19.25",
"@dashevo/dpp": "~0.21.0-dev.4",
"@dashevo/wallet-lib": "~7.21.0-dev.6",
"@dashevo/grpc-common": "~0.5.0",
"@dashevo/wallet-lib": "~7.21.0-dev.7",
"bs58": "^4.0.1",
"node-inspect-extracted": "1.0.7"
},
Expand Down
4 changes: 0 additions & 4 deletions src/SDK/Client/Client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ describe('Dash - Client', function suite() {
expect(error).to.be.an.instanceOf(StateTransitionBroadcastError);
expect(error.getCode()).to.be.equal(errorResponse.error.code);
expect(error.getMessage()).to.be.equal(errorResponse.error.message);
expect(error.getData()).to.be.equal(errorResponse.error.data);

const importedIdentityIds = account.identities.getIdentityIds();
// Check that no identities were imported
Expand Down Expand Up @@ -226,7 +225,6 @@ describe('Dash - Client', function suite() {
expect(error).to.be.an.instanceOf(StateTransitionBroadcastError);
expect(error.getCode()).to.be.equal(errorResponse.error.code);
expect(error.getMessage()).to.be.equal(errorResponse.error.message);
expect(error.getData()).to.be.equal(errorResponse.error.data);
});
});

Expand Down Expand Up @@ -254,7 +252,6 @@ describe('Dash - Client', function suite() {
expect(error).to.be.an.instanceOf(StateTransitionBroadcastError);
expect(error.getCode()).to.be.equal(errorResponse.error.code);
expect(error.getMessage()).to.be.equal(errorResponse.error.message);
expect(error.getData()).to.be.equal(errorResponse.error.data);
});

it('should broadcast documents', async () => {
Expand Down Expand Up @@ -303,7 +300,6 @@ describe('Dash - Client', function suite() {
expect(error).to.be.an.instanceOf(StateTransitionBroadcastError);
expect(error.getCode()).to.be.equal(errorResponse.error.code);
expect(error.getMessage()).to.be.equal(errorResponse.error.message);
expect(error.getData()).to.be.equal(errorResponse.error.data);
});

it('should broadcast data contract', async () => {
Expand Down
76 changes: 44 additions & 32 deletions src/SDK/Client/Platform/broadcastStateTransition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import { StateTransitionBroadcastError } from "../../../errors/StateTransitionBr
import { IStateTransitionResult } from "./IStateTransitionResult";
import { IPlatformStateProof } from "./IPlatformStateProof";

const ResponseError = require('@dashevo/dapi-client/lib/transport/errors/response/ResponseError');
const InvalidRequestDPPError = require('@dashevo/dapi-client/lib/transport/errors/response/InvalidRequestDPPError');

const createGrpcTransportError = require('@dashevo/dapi-client/lib/transport/GrpcTransport/createGrpcTransportError');

const GrpcError = require('@dashevo/grpc-common/lib/server/error/GrpcError');

/**
* @param {Platform} platform
* @param stateTransition
Expand All @@ -14,7 +21,13 @@ export default async function broadcastStateTransition(platform: Platform, state
const result = await dpp.stateTransition.validateBasic(stateTransition);

if (!result.isValid()) {
throw new Error(`StateTransition is invalid - ${JSON.stringify(result.getErrors())}`);
const consensusError = result.getFirstError();

throw new StateTransitionBroadcastError(
consensusError.getCode(),
consensusError.message,
consensusError,
);
}

// Subscribing to future result
Expand All @@ -26,40 +39,24 @@ export default async function broadcastStateTransition(platform: Platform, state

try {
await client.getDAPIClient().platform.broadcastStateTransition(serializedStateTransition);
} catch (e) {
let data;
let message;

if (e.data) {
data = e.data;
} else if (e.metadata) {
// Due to an unknown bug in the minifier, `get` method of the metadata can be stripped off.
// See the comment in the 'else' branch for more details
if (typeof e.metadata.get === 'function') {
const errors = e.metadata.get('errors');
data = {};
data.errors = errors && errors.length > 0 ? JSON.parse(errors) : errors;
} else {
// This code can be executed only if deserialization failed and no errors
// were provided in the metadata, so we can deserialize here again
// and see the details locally
try {
await dpp.stateTransition.createFromBuffer(serializedStateTransition);
} catch (deserializationError) {
data = {};
data.errors = deserializationError.errors;
data.rawStateTransition = deserializationError.rawStateTransition;
}
} catch (error) {
if (error instanceof ResponseError) {
let cause = error;

// Pass DPP consensus error directly to avoid
// additional wrappers
if (cause instanceof InvalidRequestDPPError) {
cause = cause.getConsensusError();
}
}

if (e.details) {
message = e.details;
} else {
message = e.message;
throw new StateTransitionBroadcastError(
cause.getCode(),
cause.message,
cause,
);
}

throw new StateTransitionBroadcastError(e.code, message, data);
throw error;
}

// Waiting for result to return
Expand All @@ -68,7 +65,22 @@ export default async function broadcastStateTransition(platform: Platform, state
let { error } = stateTransitionResult;

if (error) {
throw new StateTransitionBroadcastError(error.code, error.message, error.data);
// Create DAPI response error from gRPC error passed as gRPC response
const grpcError = new GrpcError(error.code, error.message, error.data);

let cause = createGrpcTransportError(grpcError);

// Pass DPP consensus error directly to avoid
// additional wrappers
if (cause instanceof InvalidRequestDPPError) {
cause = cause.getConsensusError();
}

throw new StateTransitionBroadcastError(
cause.getCode(),
cause.message,
cause,
);
}

return stateTransitionResult.proof;
Expand Down
2 changes: 1 addition & 1 deletion src/SDK/Client/Platform/methods/contracts/get.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Identifier from "@dashevo/dpp/lib/Identifier";
import 'mocha';
import { ClientApps } from "../../../ClientApps";
const GetDataContractResponse = require("@dashevo/dapi-client/lib/methods/platform/getDataContract/GetDataContractResponse");
const NotFoundError = require('@dashevo/dapi-client/lib/errors/response/NotFoundError');
const NotFoundError = require('@dashevo/dapi-client/lib/transport/GrpcTransport/errors/NotFoundError');

const factory = new DataContractFactory(
undefined,
Expand Down
2 changes: 1 addition & 1 deletion src/SDK/Client/Platform/methods/contracts/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {Platform} from "../../Platform";
// @ts-ignore
import Identifier from "@dashevo/dpp/lib/Identifier";
import Metadata from "@dashevo/dpp/lib/Metadata";
const NotFoundError = require('@dashevo/dapi-client/lib/errors/response/NotFoundError');
const NotFoundError = require('@dashevo/dapi-client/lib/transport/GrpcTransport/errors/NotFoundError');

declare type ContractIdentifier = string | Identifier;

Expand Down
2 changes: 1 addition & 1 deletion src/SDK/Client/Platform/methods/identities/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Platform} from "../../Platform";
// @ts-ignore
import Identifier from "@dashevo/dpp/lib/Identifier";
import Metadata from "@dashevo/dpp/lib/Metadata";
const NotFoundError = require('@dashevo/dapi-client/lib/errors/response/NotFoundError');
const NotFoundError = require('@dashevo/dapi-client/lib/transport/GrpcTransport/errors/NotFoundError');

/**
* Get an identity from the platform
Expand Down
33 changes: 10 additions & 23 deletions src/errors/StateTransitionBroadcastError.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
export class StateTransitionBroadcastError extends Error {
code: number;
message: string;
data: any;
cause: Error;

/**
*
* @param {number} code
* @param {string} message
* @param {*} data
* @param {Error} cause
*/
constructor(code: number, message: string, data: any) {
let detailedMessage = message;

if (data && data.errors && data.errors.length > 0) {
const [firstError] = data.errors;

detailedMessage += `: ${firstError.name}: ${firstError.message}`;

if (data.errors.length > 1) {
detailedMessage += ` and ${data.errors.length} more`;
}
}

super(detailedMessage);
constructor(code: number, message: string, cause: Error) {
super(message);

this.code = code;
this.message = detailedMessage;
this.data = data;
this.message = message;
this.cause = cause;

if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
Expand Down Expand Up @@ -54,11 +41,11 @@ export class StateTransitionBroadcastError extends Error {
}

/**
* Get error data
* Get error that was a cause
*
* @return {*}
* @return {Error}
*/
getData(): any {
return this.data;
getCause(): any {
return this.cause;
}
}

0 comments on commit c58f3cf

Please sign in to comment.