Skip to content
This repository was archived by the owner on Jul 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/__test__/integration/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,23 @@ describe('Typescript usage suite', () => {
instruction: 'call %init_peer_id% ("peer" "identify") [] res',
});
});

it('Should throw correct error when the client tries to send a particle not to the relay', async () => {
// arrange
client = await createClient();

// act
const [req, promise] = new RequestFlowBuilder()
.withRawScript('(call "incorrect_peer_id" ("any" "service") [])')
.buildWithErrorHandling();

await client.initiateFlow(req);

// assert
await expect(promise).rejects.toMatch(
'Particle is expected to be sent to only the single peer (relay which client is connected to)',
);
});
});

async function callIdentifyOnInitPeerId(client: FluenceClient): Promise<string[]> {
Expand Down
4 changes: 2 additions & 2 deletions src/internal/ClientImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class ClientImpl implements FluenceClient {
request.handler.combineWith(this.aquaCallHandler);
this.requests.set(request.id, request);

await this.processRequest(request);
this.processRequest(request);
}

async executeIncomingParticle(particle: Particle) {
Expand All @@ -130,7 +130,7 @@ export class ClientImpl implements FluenceClient {
await this.processRequest(request);
}

private async processRequest(request: RequestFlow): Promise<void> {
private processRequest(request: RequestFlow) {
try {
this.currentRequestId = request.id;
request.execute(this.interpreter, this.connection, this.relayPeerId);
Expand Down
22 changes: 17 additions & 5 deletions src/internal/FluenceConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ export interface FluenceConnectionOptions {
dialTimeout?: number;
}

export class VersionIncompatibleError extends Error {
constructor() {
super('Current version of JS SDK is incompatible with the connected Fluence node. Please update JS SDK');
}
}

export class FluenceConnection {
private readonly selfPeerId: PeerId;
private node: Peer;
Expand Down Expand Up @@ -89,7 +95,7 @@ export class FluenceConnection {

private async createPeer(options?: FluenceConnectionOptions) {
const peerInfo = this.selfPeerId;
const transportKey = Websockets.prototype[Symbol.toStringTag]
const transportKey = Websockets.prototype[Symbol.toStringTag];
this.node = await Peer.create({
peerId: peerInfo,
modules: {
Expand All @@ -100,9 +106,9 @@ export class FluenceConnection {
config: {
transport: {
[transportKey]: {
filter: allow_all
}
}
filter: allow_all,
},
},
},
dialer: {
timeout: options?.dialTimeout,
Expand All @@ -116,7 +122,13 @@ export class FluenceConnection {

log.trace(`dialing to the node with client's address: ` + this.node.peerId.toB58String());

await this.node.dial(this.address);
try {
await this.node.dial(this.address);
} catch (e) {
if (e.name === 'AggregateError' && e._errors[0].code === 'ERR_ENCRYPTION_FAILED') {
throw new VersionIncompatibleError();
}
}

let _this = this;

Expand Down
21 changes: 14 additions & 7 deletions src/internal/RequestFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class RequestFlow {
const interpreterOutcome = this.runInterpreter(interpreter);

log.debug('inner interpreter outcome:', {
particleId: this.getParticle()?.id,
ret_code: interpreterOutcome.ret_code,
error_message: interpreterOutcome.error_message,
next_peer_pks: interpreterOutcome.next_peer_pks,
Expand All @@ -86,25 +87,31 @@ export class RequestFlow {

// we only expect a single possible peer id to send particle further
if (nextPeers.length > 1) {
throw new Error(
'Particle is expected to be sent to only the single peer (relay which client is connected to)',
);
this.throwIncorrectNextPeerPks(nextPeers);
}

// this peer id must be the relay, the client is connected to
if (!relayPeerId || nextPeers[0] !== relayPeerId) {
throw new Error(
'Particle is expected to be sent to only the single peer (relay which client is connected to)',
);
this.throwIncorrectNextPeerPks(nextPeers);
}

if (!connection) {
throw new Error('Cannot send particle: non connected');
this.raiseError('Cannot send particle: non connected');
}

this.sendIntoConnection(connection);
}

private throwIncorrectNextPeerPks(nextPeers: PeerIdB58[]) {
this.raiseError(
`Particle is expected to be sent to only the single peer (relay which client is connected to).
particle id: ${this.getParticle()?.id}
next peers: ${nextPeers.join(' ')}
relay peer id: ${this.relayPeerId}
`,
);
}

async initState(peerId: PeerId): Promise<void> {
const id = this.id;
let currentTime = Date.now();
Expand Down