Skip to content

Commit c65c0af

Browse files
authored
Xor (#24)
* Wrapping scripts with xor * Add function subscribeForErrors to handle errors
1 parent 619c8a6 commit c65c0af

File tree

8 files changed

+122
-24
lines changed

8 files changed

+122
-24
lines changed

src/__test__/integration/builtins.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
} from '../../internal/builtins';
1111
import { ModuleConfig } from '../../internal/moduleConfig';
1212
import { checkConnection } from '../../api';
13-
import log from 'loglevel';
1413
import { generatePeerId } from '../..';
1514
import { FluenceClientImpl } from '../../internal/FluenceClientImpl';
1615
import { createConnectedClient, nodes } from '../connection';

src/__test__/integration/client.spec.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { encode } from 'bs58';
22
import { generatePeerId, peerIdToSeed, seedToPeerId } from '../../internal/peerIdUtils';
33
import { FluenceClientImpl } from '../../internal/FluenceClientImpl';
44
import log from 'loglevel';
5-
import { createClient } from '../../api';
5+
import { createClient, subscribeForErrors } from '../../api';
66
import Multiaddr from 'multiaddr';
7-
import { createConnectedClient, nodes } from '../connection';
7+
import { createConnectedClient, createLocalClient, nodes } from '../connection';
88

99
describe('Typescript usage suite', () => {
1010
it('should create private key from seed and back', async function () {
@@ -219,4 +219,46 @@ describe('Typescript usage suite', () => {
219219
let res = await resMakingPromise;
220220
expect(res).toEqual(['some a', 'some b', 'some c', 'some d']);
221221
});
222+
223+
it('xor handling should work with connected client', async function () {
224+
// arrange
225+
const client = await createConnectedClient(nodes[0].multiaddr);
226+
log.setLevel('info');
227+
228+
// act
229+
let script = `
230+
(seq
231+
(call relay ("op" "identity") [])
232+
(call relay ("incorrect" "service") ["incorrect_arg"])
233+
)
234+
`;
235+
const data = new Map();
236+
data.set('relay', client.relayPeerId);
237+
238+
const promise = subscribeForErrors(client, 7000);
239+
await client.sendScript(script, data);
240+
241+
// assert
242+
await expect(promise).rejects.toMatchObject({
243+
error: expect.stringContaining("Service with id 'incorrect' not found"),
244+
instruction: expect.stringContaining('incorrect'),
245+
});
246+
});
247+
248+
it('xor handling should work with local client', async function () {
249+
// arrange
250+
const client = await createLocalClient();
251+
252+
// act
253+
let script = `(call %init_peer_id% ("incorrect" "service") ["incorrect_arg"])`;
254+
255+
const promise = subscribeForErrors(client, 7000);
256+
await client.sendScript(script);
257+
258+
// assert
259+
await expect(promise).rejects.toMatchObject({
260+
error: expect.stringContaining('There is no service: incorrect'),
261+
instruction: expect.stringContaining('incorrect'),
262+
});
263+
});
222264
});

src/__test__/unit/air.spec.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,27 +45,39 @@ describe('== AIR suite', () => {
4545
});
4646

4747
it('call broken script', async function () {
48+
// arrange
4849
const client = await createLocalClient();
50+
const script = `(incorrect)`;
4951

50-
const script = `(htyth)`;
52+
// act
53+
const promise = client.sendScript(script);
5154

52-
await expect(client.sendScript(script)).rejects.toContain("aqua script can't be parsed");
55+
// assert
56+
await expect(promise).rejects.toContain("aqua script can't be parsed");
5357
});
5458

5559
it('call script without ttl', async function () {
60+
// arrange
5661
const client = await createLocalClient();
57-
5862
const script = `(call %init_peer_id% ("" "") [""])`;
5963

60-
await expect(client.sendScript(script, undefined, 1)).rejects.toContain('Particle expired');
64+
// act
65+
const promise = client.sendScript(script, undefined, 1);
66+
67+
// assert
68+
await expect(promise).rejects.toContain('Particle expired');
6169
});
6270

6371
it.skip('call broken script by fetch', async function () {
72+
// arrange
6473
const client = await createLocalClient();
74+
const script = `(incorrect)`;
6575

66-
const script = `(htyth)`;
76+
// act
77+
const promise = client.fetch(script, ['result']);
6778

68-
await expect(client.fetch(script, ['result'])).rejects.toContain("aqua script can't be parsed");
79+
// assert
80+
await expect(promise).rejects.toContain("aqua script can't be parsed");
6981
});
7082

7183
it('check particle arguments', async function () {

src/api.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,25 @@ export const checkConnection = async (client: FluenceClient): Promise<boolean> =
190190
return false;
191191
}
192192
};
193+
194+
export const subscribeForErrors = (client: FluenceClient, ttl: number): Promise<void> => {
195+
return new Promise((resolve, reject) => {
196+
registerServiceFunction(client, '__magic', 'handle_xor', (args, _) => {
197+
setTimeout(() => {
198+
try {
199+
reject(JSON.parse(args[0]));
200+
} catch {
201+
reject(args);
202+
}
203+
}, 0);
204+
205+
unregisterServiceFunction(client, '__magic', 'handle_xor');
206+
return {};
207+
});
208+
209+
setTimeout(() => {
210+
unregisterServiceFunction(client, '__magic', 'handle_xor');
211+
resolve();
212+
}, ttl);
213+
});
214+
};

src/internal/FluenceClientBase.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { PeerIdB58 } from './commonTypes';
2626
export abstract class FluenceClientBase {
2727
readonly selfPeerIdFull: PeerId;
2828

29-
get relayPeerId(): PeerIdB58 {
29+
get relayPeerId(): PeerIdB58 | undefined {
3030
return this.connection?.nodePeerId.toB58String();
3131
}
3232

@@ -88,7 +88,7 @@ export abstract class FluenceClientBase {
8888
}
8989

9090
async sendScript(script: string, data?: Map<string, any>, ttl?: number): Promise<string> {
91-
const particle = await build(this.selfPeerIdFull, script, data, ttl);
91+
const particle = await build(this.selfPeerIdFull, this.relayPeerId, script, data, ttl);
9292
await this.processor.executeLocalParticle(particle);
9393
return particle.id;
9494
}

src/internal/FluenceClientImpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class FluenceClientImpl extends FluenceClientBase implements FluenceClien
7171
data = this.addRelayToArgs(data);
7272
const callBackId = genUUID();
7373
script = wrapFetchCall(script, callBackId, resultArgNames);
74-
const particle = await build(this.selfPeerIdFull, script, data, ttl, callBackId);
74+
const particle = await build(this.selfPeerIdFull, this.relayPeerId, script, data, ttl, callBackId);
7575

7676
const prFetch = new Promise<T>(async (resolve, reject) => {
7777
this.fetchParticles.set(callBackId, { resolve, reject });

src/internal/ParticleProcessor.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,17 @@ export class ParticleProcessor {
7777
// TODO: destroy interpreter
7878
}
7979

80-
async executeLocalParticle(particle: ParticleDto) {
80+
async executeLocalParticle(particle: ParticleDto): Promise<void> {
8181
this.strategy?.onLocalParticleRecieved(particle);
8282
return new Promise<void>((resolve, reject) => {
83-
const resolveCallback = function () {
84-
resolve();
85-
};
86-
const rejectCallback = function (err: any) {
87-
reject(err);
88-
};
8983
// we check by callbacks that the script passed through the interpreter without errors
90-
this.handleParticle(particle, resolveCallback, rejectCallback);
84+
this.handleParticle(particle, resolve, reject);
9185
});
9286
}
9387

94-
async executeExternalParticle(particle: ParticleDto) {
88+
async executeExternalParticle(particle: ParticleDto): Promise<void> {
9589
this.strategy?.onExternalParticleRecieved(particle);
96-
await this.handleExternalParticle(particle);
90+
return await this.handleExternalParticle(particle);
9791
}
9892

9993
/*
@@ -231,7 +225,7 @@ export class ParticleProcessor {
231225
if (nextParticle) {
232226
// update current particle
233227
this.setCurrentParticleId(nextParticle.id);
234-
await this.handleParticle(nextParticle);
228+
return await this.handleParticle(nextParticle);
235229
} else {
236230
// wait for a new call (do nothing) if there is no new particle in a queue
237231
this.setCurrentParticleId(undefined);
@@ -249,7 +243,7 @@ export class ParticleProcessor {
249243
if (error !== undefined) {
250244
log.error('error in external particle: ', error);
251245
} else {
252-
await this.handleParticle(particle);
246+
return await this.handleParticle(particle);
253247
}
254248
}
255249

src/internal/particle.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { fromByteArray, toByteArray } from 'base64-js';
1919
import PeerId from 'peer-id';
2020
import { encode } from 'bs58';
2121
import { injectDataIntoParticle } from './ParticleProcessor';
22+
import { PeerIdB58 } from './commonTypes';
2223

2324
const DEFAULT_TTL = 7000;
2425

@@ -91,8 +92,28 @@ function wrapWithVariableInjectionScript(script: string, fields: string[]): stri
9192
return script;
9293
}
9394

95+
function wrapWithXor(script: string): string {
96+
return `
97+
(xor
98+
${script}
99+
(seq
100+
(call __magic_relay ("op" "identity") [])
101+
(call %init_peer_id% ("__magic" "handle_xor") [%last_error%])
102+
)
103+
)`;
104+
}
105+
106+
function wrapWithXorLocal(script: string): string {
107+
return `
108+
(xor
109+
${script}
110+
(call %init_peer_id% ("__magic" "handle_xor") [%last_error%])
111+
)`;
112+
}
113+
94114
export async function build(
95115
peerId: PeerId,
116+
relay: PeerIdB58 | undefined,
96117
script: string,
97118
data?: Map<string, any>,
98119
ttl?: number,
@@ -109,8 +130,16 @@ export async function build(
109130
ttl = DEFAULT_TTL;
110131
}
111132

133+
if (relay) {
134+
data.set('__magic_relay', relay);
135+
}
112136
injectDataIntoParticle(id, data, ttl);
113137
script = wrapWithVariableInjectionScript(script, Array.from(data.keys()));
138+
if (relay) {
139+
script = wrapWithXor(script);
140+
} else {
141+
script = wrapWithXorLocal(script);
142+
}
114143

115144
let particle: ParticleDto = {
116145
id: id,

0 commit comments

Comments
 (0)