mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2025-06-01 10:11:22 +00:00
fix(chore): Additional test for particle signature (#356)
* Additional test for particle signature * remove .only * Fix bs58 * Fix bs58 #2 * update test * update test * fix test * remove only * refactor * refactor --------- Co-authored-by: Aleksey Proshutisnkiy <justprosh@users.noreply.github.com> Co-authored-by: Alexey Proshutinskiy <alexey.prosh@fluence.one>
This commit is contained in:
parent
c0b73fec4a
commit
230f47d27e
@ -34,7 +34,7 @@ import { Subject } from 'rxjs';
|
||||
import { throwIfHasNoPeerId } from '../util/libp2pUtils.js';
|
||||
import { IConnection } from './interfaces.js';
|
||||
import { IParticle } from '../particle/interfaces.js';
|
||||
import { Particle, serializeToString, verifySignature } from '../particle/Particle.js';
|
||||
import { buildParticleMessage, Particle, serializeToString, verifySignature } from '../particle/Particle.js';
|
||||
import { identifyService } from 'libp2p/identify';
|
||||
import { pingService } from 'libp2p/ping';
|
||||
import { unmarshalPublicKey } from '@libp2p/crypto/keys';
|
||||
@ -186,7 +186,9 @@ export class RelayConnection implements IConnection {
|
||||
return;
|
||||
}
|
||||
|
||||
const isVerified = await verifySignature(particle, initPeerId.publicKey);
|
||||
// TODO: uncomment this after nox rolls out signature verification
|
||||
// const isVerified = await KeyPair.verifyWithPublicKey(initPeerId.publicKey, buildParticleMessage(particle), particle.signature);
|
||||
const isVerified = true;
|
||||
if (isVerified) {
|
||||
this.particleSource.next(particle);
|
||||
} else {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright 2023 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -13,15 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { it, describe, expect } from 'vitest';
|
||||
import { toUint8Array } from 'js-base64';
|
||||
import * as bs58 from 'bs58';
|
||||
import { KeyPair } from '../index.js';
|
||||
|
||||
// @ts-ignore
|
||||
const { decode } = bs58.default;
|
||||
import bs58 from "bs58";
|
||||
import { fromUint8Array, toUint8Array } from 'js-base64';
|
||||
import { it, describe, expect } from "vitest";
|
||||
import { fromBase64Sk, KeyPair } from '../index.js';
|
||||
|
||||
const key = '+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk=';
|
||||
import { Particle, serializeToString, buildParticleMessage } from '../../particle/Particle.js';
|
||||
|
||||
const key = "+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk=";
|
||||
const keyBytes = toUint8Array(key);
|
||||
|
||||
const testData = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 9, 10]);
|
||||
@ -34,76 +34,102 @@ const testDataSig = Uint8Array.from([
|
||||
|
||||
// signature produced by KeyPair created from some random KeyPair
|
||||
|
||||
describe('KeyPair tests', () => {
|
||||
it('generate keypair from seed', async function () {
|
||||
// arrange
|
||||
const random = await KeyPair.randomEd25519();
|
||||
const privateKey = random.toEd25519PrivateKey();
|
||||
describe("KeyPair tests", () => {
|
||||
it("generate keypair from seed", async function () {
|
||||
// arrange
|
||||
const random = await KeyPair.randomEd25519();
|
||||
const privateKey = random.toEd25519PrivateKey();
|
||||
|
||||
// act
|
||||
const keyPair = await KeyPair.fromEd25519SK(privateKey);
|
||||
const privateKey2 = keyPair.toEd25519PrivateKey();
|
||||
// act
|
||||
const keyPair = await KeyPair.fromEd25519SK(privateKey);
|
||||
const privateKey2 = keyPair.toEd25519PrivateKey();
|
||||
|
||||
// assert
|
||||
expect(privateKey).toStrictEqual(privateKey2);
|
||||
});
|
||||
// assert
|
||||
expect(privateKey).toStrictEqual(privateKey2);
|
||||
});
|
||||
|
||||
it('create keypair from ed25519 private key', async function () {
|
||||
// arrange
|
||||
const rustSK = 'jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH';
|
||||
const sk = decode(rustSK);
|
||||
it("create keypair from ed25519 private key", async function () {
|
||||
// arrange
|
||||
const rustSK = "jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH";
|
||||
const sk = bs58.decode(rustSK);
|
||||
|
||||
// act
|
||||
const keyPair = await KeyPair.fromEd25519SK(sk);
|
||||
// act
|
||||
const keyPair = await KeyPair.fromEd25519SK(sk);
|
||||
|
||||
// assert
|
||||
const expectedPeerId = '12D3KooWH1W3VznVZ87JH4FwABK4mkntcspTVWJDta6c2xg9Pzbp';
|
||||
expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId);
|
||||
});
|
||||
// assert
|
||||
const expectedPeerId =
|
||||
"12D3KooWH1W3VznVZ87JH4FwABK4mkntcspTVWJDta6c2xg9Pzbp";
|
||||
|
||||
it('create keypair from a seed phrase', async function () {
|
||||
// arrange
|
||||
const seedArray = new Uint8Array(32).fill(1);
|
||||
expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId);
|
||||
});
|
||||
|
||||
// act
|
||||
const keyPair = await KeyPair.fromEd25519SK(seedArray);
|
||||
it("create keypair from a seed phrase", async function () {
|
||||
// arrange
|
||||
const seedArray = new Uint8Array(32).fill(1);
|
||||
|
||||
// assert
|
||||
const expectedPeerId = '12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5';
|
||||
expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId);
|
||||
});
|
||||
// act
|
||||
const keyPair = await KeyPair.fromEd25519SK(seedArray);
|
||||
|
||||
it('sign', async function () {
|
||||
// arrange
|
||||
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
|
||||
// assert
|
||||
const expectedPeerId =
|
||||
"12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5";
|
||||
|
||||
// act
|
||||
const res = await keyPair.signBytes(testData);
|
||||
// assert
|
||||
expect(new Uint8Array(res)).toStrictEqual(testDataSig);
|
||||
});
|
||||
expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId);
|
||||
});
|
||||
|
||||
it('verify', async function () {
|
||||
// arrange
|
||||
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
|
||||
it("sign", async function () {
|
||||
// arrange
|
||||
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
|
||||
|
||||
// act
|
||||
const res = await keyPair.verify(testData, testDataSig);
|
||||
// act
|
||||
const res = await keyPair.signBytes(testData);
|
||||
// assert
|
||||
expect(new Uint8Array(res)).toStrictEqual(testDataSig);
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
it("verify", async function () {
|
||||
// arrange
|
||||
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
|
||||
|
||||
it('sign-verify', async function () {
|
||||
// arrange
|
||||
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
|
||||
// act
|
||||
const res = await keyPair.verify(testData, testDataSig);
|
||||
|
||||
// act
|
||||
const data = new Uint8Array(32).fill(1);
|
||||
const sig = await keyPair.signBytes(data);
|
||||
const res = await keyPair.verify(data, sig);
|
||||
// assert
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
it("sign-verify", async function () {
|
||||
// arrange
|
||||
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
|
||||
|
||||
// act
|
||||
const data = new Uint8Array(32).fill(1);
|
||||
const sig = await keyPair.signBytes(data);
|
||||
const res = await keyPair.verify(data, sig);
|
||||
|
||||
// assert
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it("validates particle signature checks", async function () {
|
||||
const keyPair = await fromBase64Sk("7h48PQ/f1rS9TxacmgODxbD42Il9B3KC117jvOPppPE=");
|
||||
expect(bs58.encode(keyPair.getLibp2pPeerId().toBytes())).toBe("12D3KooWANqfCDrV79MZdMnMqTvDdqSAPSxdgFY1L6DCq2DVGB4D");
|
||||
const message = toUint8Array(btoa("message"));
|
||||
const signature = await keyPair.signBytes(message);
|
||||
|
||||
const verified = await keyPair.verify(message, signature);
|
||||
expect(verified).toBe(true);
|
||||
expect(fromUint8Array(signature)).toBe("sBW7H6/1fwAwF86ldwVm9BDu0YH3w30oFQjTWX0Tiu9yTVZHmxkV2OX4GL5jn0Iz0CrasGcOfozzkZwtJBPMBg==");
|
||||
|
||||
const particle = await Particle.createNew("abc", keyPair.getPeerId(), 7000, keyPair, "2883f959-e9e7-4843-8c37-205d393ca372", 1696934545662);
|
||||
|
||||
const particle_bytes = buildParticleMessage(particle);
|
||||
expect(fromUint8Array(particle_bytes)).toBe("Mjg4M2Y5NTktZTllNy00ODQzLThjMzctMjA1ZDM5M2NhMzcy/kguGYsBAABYGwAAYWJj");
|
||||
|
||||
const isParticleVerified = await KeyPair.verifyWithPublicKey(keyPair.getPublicKey(), particle_bytes, particle.signature);
|
||||
|
||||
expect(isParticleVerified).toBe(true);
|
||||
|
||||
expect(fromUint8Array(particle.signature)).toBe("KceXDnOfqe0dOnAxiDsyWBIvUq6WHoT0ge+VMHXOZsjZvCNH7/10oufdlYfcPomfv28On6E87ZhDcHGBZcb7Bw==");
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
/**
|
||||
* Copyright 2023 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,92 +14,105 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { PeerId } from '@libp2p/interface/peer-id';
|
||||
import { generateKeyPairFromSeed, generateKeyPair, unmarshalPublicKey } from '@libp2p/crypto/keys';
|
||||
import { createFromPrivKey, createFromPubKey } from '@libp2p/peer-id-factory';
|
||||
import type { PrivateKey, PublicKey } from '@libp2p/interface/keys';
|
||||
import { toUint8Array } from 'js-base64';
|
||||
import * as bs58 from 'bs58';
|
||||
import { KeyPairOptions } from '@fluencelabs/interfaces';
|
||||
|
||||
// @ts-ignore
|
||||
const { decode } = bs58.default;
|
||||
import { KeyPairOptions } from "@fluencelabs/interfaces";
|
||||
import {
|
||||
generateKeyPairFromSeed,
|
||||
generateKeyPair,
|
||||
unmarshalPublicKey,
|
||||
} from "@libp2p/crypto/keys";
|
||||
import type { PrivateKey, PublicKey } from "@libp2p/interface/keys";
|
||||
import type { PeerId } from "@libp2p/interface/peer-id";
|
||||
import { createFromPrivKey } from "@libp2p/peer-id-factory";
|
||||
import bs58 from "bs58";
|
||||
import { toUint8Array } from "js-base64";
|
||||
|
||||
export class KeyPair {
|
||||
/**
|
||||
* Key pair in libp2p format. Used for backward compatibility with the current FluencePeer implementation
|
||||
*/
|
||||
getLibp2pPeerId() {
|
||||
return this.libp2pPeerId;
|
||||
}
|
||||
private publicKey: PublicKey;
|
||||
|
||||
constructor(
|
||||
private privateKey: PrivateKey | undefined,
|
||||
private publicKey: PublicKey,
|
||||
private libp2pPeerId: PeerId
|
||||
) {}
|
||||
private constructor(
|
||||
private privateKey: PrivateKey,
|
||||
private libp2pPeerId: PeerId,
|
||||
) {
|
||||
this.publicKey = privateKey.public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates new KeyPair from ed25519 private key represented as a 32 byte array
|
||||
* @param seed - Any sequence of 32 bytes
|
||||
* @returns - Promise with the created KeyPair
|
||||
*/
|
||||
static async fromEd25519SK(seed: Uint8Array): Promise<KeyPair> {
|
||||
const key = await generateKeyPairFromSeed('Ed25519', seed, 256);
|
||||
const lib2p2Pid = await createFromPrivKey(key);
|
||||
return new KeyPair(key, key.public, lib2p2Pid);
|
||||
}
|
||||
/**
|
||||
* Key pair in libp2p format. Used for backward compatibility with the current FluencePeer implementation
|
||||
*/
|
||||
getLibp2pPeerId() {
|
||||
return this.libp2pPeerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates new KeyPair with a random secret key
|
||||
* @returns - Promise with the created KeyPair
|
||||
*/
|
||||
static async randomEd25519(): Promise<KeyPair> {
|
||||
const key = await generateKeyPair('Ed25519');
|
||||
const lib2p2Pid = await createFromPrivKey(key);
|
||||
return new KeyPair(key, key.public, lib2p2Pid);
|
||||
}
|
||||
/**
|
||||
* Return public key inferred from private key
|
||||
*/
|
||||
getPublicKey() {
|
||||
return this.publicKey.bytes;
|
||||
}
|
||||
|
||||
getPeerId(): string {
|
||||
return this.libp2pPeerId.toString();
|
||||
}
|
||||
/**
|
||||
* Generates new KeyPair from ed25519 private key represented as a 32 byte array
|
||||
* @param seed - Any sequence of 32 bytes
|
||||
* @returns - Promise with the created KeyPair
|
||||
*/
|
||||
static async fromEd25519SK(seed: Uint8Array): Promise<KeyPair> {
|
||||
const key = await generateKeyPairFromSeed("Ed25519", seed, 256);
|
||||
const lib2p2Pid = await createFromPrivKey(key);
|
||||
return new KeyPair(key, lib2p2Pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 32 byte private key
|
||||
*/
|
||||
toEd25519PrivateKey(): Uint8Array {
|
||||
if (this.privateKey === undefined) {
|
||||
throw new Error('Private key not supplied');
|
||||
}
|
||||
return this.privateKey.marshal().subarray(0, 32);
|
||||
}
|
||||
/**
|
||||
* Generates new KeyPair with a random secret key
|
||||
* @returns - Promise with the created KeyPair
|
||||
*/
|
||||
static async randomEd25519(): Promise<KeyPair> {
|
||||
const key = await generateKeyPair("Ed25519");
|
||||
const lib2p2Pid = await createFromPrivKey(key);
|
||||
return new KeyPair(key, lib2p2Pid);
|
||||
}
|
||||
|
||||
signBytes(data: Uint8Array): Promise<Uint8Array> {
|
||||
if (this.privateKey === undefined) {
|
||||
throw new Error('Private key not supplied');
|
||||
}
|
||||
return this.privateKey.sign(data);
|
||||
}
|
||||
static verifyWithPublicKey(
|
||||
publicKey: Uint8Array,
|
||||
message: Uint8Array,
|
||||
signature: Uint8Array,
|
||||
) {
|
||||
return unmarshalPublicKey(publicKey).verify(message, signature);
|
||||
}
|
||||
|
||||
verify(data: Uint8Array, signature: Uint8Array): Promise<boolean> {
|
||||
return this.publicKey.verify(data, signature);
|
||||
}
|
||||
getPeerId(): string {
|
||||
return this.libp2pPeerId.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 32 byte private key
|
||||
*/
|
||||
toEd25519PrivateKey(): Uint8Array {
|
||||
return this.privateKey.marshal().subarray(0, 32);
|
||||
}
|
||||
|
||||
signBytes(data: Uint8Array): Promise<Uint8Array> {
|
||||
return this.privateKey.sign(data);
|
||||
}
|
||||
|
||||
verify(data: Uint8Array, signature: Uint8Array): Promise<boolean> {
|
||||
return this.publicKey.verify(data, signature);
|
||||
}
|
||||
}
|
||||
|
||||
export const fromBase64Sk = (sk: string): Promise<KeyPair> => {
|
||||
const skArr = toUint8Array(sk);
|
||||
return KeyPair.fromEd25519SK(skArr);
|
||||
const skArr = toUint8Array(sk);
|
||||
return KeyPair.fromEd25519SK(skArr);
|
||||
};
|
||||
|
||||
export const fromBase58Sk = (sk: string): Promise<KeyPair> => {
|
||||
const skArr = decode(sk);
|
||||
return KeyPair.fromEd25519SK(skArr);
|
||||
const skArr = bs58.decode(sk);
|
||||
return KeyPair.fromEd25519SK(skArr);
|
||||
};
|
||||
|
||||
export const fromOpts = (opts: KeyPairOptions): Promise<KeyPair> => {
|
||||
if (opts.source === 'random') {
|
||||
return KeyPair.randomEd25519();
|
||||
}
|
||||
if (opts.source === "random") {
|
||||
return KeyPair.randomEd25519();
|
||||
}
|
||||
|
||||
return KeyPair.fromEd25519SK(opts.source);
|
||||
return KeyPair.fromEd25519SK(opts.source);
|
||||
};
|
||||
|
@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { atob, fromUint8Array, toUint8Array } from 'js-base64';
|
||||
import { CallResultsArray } from '@fluencelabs/avm';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Buffer } from 'buffer';
|
||||
import { IParticle } from './interfaces.js';
|
||||
import { concat } from 'uint8arrays/concat';
|
||||
import { numberToLittleEndianBytes } from '../util/bytes.js';
|
||||
import { KeyPair } from '../keypair/index.js';
|
||||
import { unmarshalPublicKey } from '@libp2p/crypto/keys';
|
||||
import { CallResultsArray } from "@fluencelabs/avm";
|
||||
import { fromUint8Array, toUint8Array } from "js-base64";
|
||||
import { concat } from "uint8arrays/concat";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { KeyPair } from "../keypair/index.js";
|
||||
import { numberToLittleEndianBytes } from "../util/bytes.js";
|
||||
|
||||
import { IParticle } from "./interfaces.js";
|
||||
|
||||
export class Particle implements IParticle {
|
||||
constructor(
|
||||
@ -34,14 +34,31 @@ export class Particle implements IParticle {
|
||||
public readonly initPeerId: string,
|
||||
public readonly signature: Uint8Array
|
||||
) {}
|
||||
|
||||
static async createNew(script: string, initPeerId: string, ttl: number, keyPair: KeyPair): Promise<Particle> {
|
||||
const id = uuidv4();
|
||||
const timestamp = Date.now();
|
||||
const message = buildParticleMessage({ id, timestamp, ttl, script });
|
||||
const signature = await keyPair.signBytes(message);
|
||||
return new Particle(id, Date.now(), script, Buffer.from([]), ttl, initPeerId, signature);
|
||||
}
|
||||
|
||||
static async createNew(
|
||||
script: string,
|
||||
initPeerId: string,
|
||||
ttl: number,
|
||||
keyPair: KeyPair,
|
||||
_id?: string,
|
||||
_timestamp?: number,
|
||||
_data?: Uint8Array,
|
||||
): Promise<Particle> {
|
||||
const id = _id ?? uuidv4();
|
||||
const timestamp = _timestamp ?? Date.now();
|
||||
const data = _data ?? new Uint8Array([]);
|
||||
const message = buildParticleMessage({ id, timestamp, ttl, script });
|
||||
const signature = await keyPair.signBytes(message);
|
||||
return new Particle(
|
||||
id,
|
||||
timestamp,
|
||||
script,
|
||||
data,
|
||||
ttl,
|
||||
initPeerId,
|
||||
signature,
|
||||
);
|
||||
}
|
||||
|
||||
static fromString(str: string): Particle {
|
||||
const json = JSON.parse(str);
|
||||
@ -64,27 +81,32 @@ const en = new TextEncoder();
|
||||
/**
|
||||
* Builds particle message for signing
|
||||
*/
|
||||
export const buildParticleMessage = ({ id, timestamp, ttl, script }: Omit<IParticle, 'initPeerId' | 'signature' | 'data'>): Uint8Array => {
|
||||
return concat([
|
||||
en.encode(id),
|
||||
numberToLittleEndianBytes(timestamp, 'u64'),
|
||||
numberToLittleEndianBytes(ttl, 'u32'),
|
||||
en.encode(script),
|
||||
]);
|
||||
}
|
||||
export const buildParticleMessage = ({
|
||||
id,
|
||||
timestamp,
|
||||
ttl,
|
||||
script,
|
||||
}: Omit<IParticle, "initPeerId" | "signature" | "data">): Uint8Array => {
|
||||
return concat([
|
||||
en.encode(id),
|
||||
numberToLittleEndianBytes(timestamp, "u64"),
|
||||
numberToLittleEndianBytes(ttl, "u32"),
|
||||
en.encode(script),
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns actual ttl of a particle, i.e. ttl - time passed since particle creation
|
||||
*/
|
||||
export const getActualTTL = (particle: IParticle): number => {
|
||||
return particle.timestamp + particle.ttl - Date.now();
|
||||
return particle.timestamp + particle.ttl - Date.now();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if particle has expired
|
||||
*/
|
||||
export const hasExpired = (particle: IParticle): boolean => {
|
||||
return getActualTTL(particle) <= 0;
|
||||
return getActualTTL(particle) <= 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -100,59 +122,65 @@ export const verifySignature = async (particle: IParticle, publicKey: Uint8Array
|
||||
/**
|
||||
* Creates a particle clone with new data
|
||||
*/
|
||||
export const cloneWithNewData = (particle: IParticle, newData: Uint8Array): IParticle => {
|
||||
return new Particle(particle.id, particle.timestamp, particle.script, newData, particle.ttl, particle.initPeerId, particle.signature);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a deep copy of a particle
|
||||
*/
|
||||
export const fullClone = (particle: IParticle): IParticle => {
|
||||
return JSON.parse(JSON.stringify(particle));
|
||||
export const cloneWithNewData = (
|
||||
particle: IParticle,
|
||||
newData: Uint8Array,
|
||||
): IParticle => {
|
||||
return new Particle(
|
||||
particle.id,
|
||||
particle.timestamp,
|
||||
particle.script,
|
||||
newData,
|
||||
particle.ttl,
|
||||
particle.initPeerId,
|
||||
particle.signature,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializes particle into string suitable for sending through network
|
||||
*/
|
||||
export const serializeToString = (particle: IParticle): string => {
|
||||
return JSON.stringify({
|
||||
action: 'Particle',
|
||||
id: particle.id,
|
||||
init_peer_id: particle.initPeerId,
|
||||
timestamp: particle.timestamp,
|
||||
ttl: particle.ttl,
|
||||
script: particle.script,
|
||||
signature: Array.from(particle.signature),
|
||||
data: particle.data && fromUint8Array(particle.data),
|
||||
});
|
||||
return JSON.stringify({
|
||||
action: "Particle",
|
||||
id: particle.id,
|
||||
init_peer_id: particle.initPeerId,
|
||||
timestamp: particle.timestamp,
|
||||
ttl: particle.ttl,
|
||||
script: particle.script,
|
||||
signature: Array.from(particle.signature),
|
||||
data: fromUint8Array(particle.data),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* When particle is executed, it goes through different stages. The type describes all possible stages and their parameters
|
||||
*/
|
||||
export type ParticleExecutionStage =
|
||||
| { stage: 'received' }
|
||||
| { stage: 'interpreted' }
|
||||
| { stage: 'interpreterError'; errorMessage: string }
|
||||
| { stage: 'localWorkDone' }
|
||||
| { stage: 'sent' }
|
||||
| { stage: 'sendingError'; errorMessage: string }
|
||||
| { stage: 'expired' };
|
||||
| { stage: "received" }
|
||||
| { stage: "interpreted" }
|
||||
| { stage: "interpreterError"; errorMessage: string }
|
||||
| { stage: "localWorkDone" }
|
||||
| { stage: "sent" }
|
||||
| { stage: "sendingError"; errorMessage: string }
|
||||
| { stage: "expired" };
|
||||
|
||||
/**
|
||||
* Particle queue item is a wrapper around particle, which contains additional information about particle execution
|
||||
*/
|
||||
export interface ParticleQueueItem {
|
||||
particle: IParticle;
|
||||
callResults: CallResultsArray;
|
||||
onStageChange: (state: ParticleExecutionStage) => void;
|
||||
particle: IParticle;
|
||||
callResults: CallResultsArray;
|
||||
onStageChange: (state: ParticleExecutionStage) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to handle particle at expired stage
|
||||
*/
|
||||
export const handleTimeout = (fn: () => void) => (stage: ParticleExecutionStage) => {
|
||||
if (stage.stage === 'expired') {
|
||||
fn();
|
||||
}
|
||||
};
|
||||
export const handleTimeout = (fn: () => void) => {
|
||||
return (stage: ParticleExecutionStage) => {
|
||||
if (stage.stage === "expired") {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,10 @@ const sizeMap = {
|
||||
|
||||
function numberToBytes(n: number, s: Size, littleEndian: boolean) {
|
||||
const size = sizeMap[s];
|
||||
const buffer = new ArrayBuffer(size);
|
||||
const buffer = new ArrayBuffer(8);
|
||||
const dv = new DataView(buffer);
|
||||
dv.setUint32(0, n, littleEndian);
|
||||
return new Uint8Array(buffer);
|
||||
dv.setBigUint64(0, BigInt(n), littleEndian);
|
||||
return new Uint8Array(buffer.slice(0, size));
|
||||
}
|
||||
|
||||
export function numberToLittleEndianBytes(n: number, s: Size) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user