diff --git a/lerna.json b/lerna.json index 1f4e30a0..af0f0a32 100644 --- a/lerna.json +++ b/lerna.json @@ -6,5 +6,5 @@ "publishConfig": { "directory": "build" }, - "version": "0.14.2" + "version": "0.15.0-alpha.11" } diff --git a/packages/node-api/package.json b/packages/node-api/package.json index 3f80b30c..f529d1c4 100644 --- a/packages/node-api/package.json +++ b/packages/node-api/package.json @@ -18,10 +18,10 @@ }, "sideEffects": false, "type": "module", - "version": "0.14.2", + "version": "0.15.0-alpha.11", "main": "index.js", "dependencies": { - "@encointer/types": "^0.14.2", + "@encointer/types": "^0.15.0-alpha.11", "@polkadot/api": "^11.2.1", "tslib": "^2.6.2" }, diff --git a/packages/types/package.json b/packages/types/package.json index a4e53461..e7e688d1 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -18,7 +18,7 @@ }, "sideEffects": false, "type": "module", - "version": "0.14.2", + "version": "0.15.0-alpha.11", "main": "index.js", "scripts": { "generate:defs": "node --experimental-specifier-resolution=node --loader ts-node/esm ../../node_modules/.bin/polkadot-types-from-defs --package @encointer/types/interfaces --input ./src/interfaces", diff --git a/packages/util/package.json b/packages/util/package.json index 51cfcd5f..84d375b5 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -20,7 +20,7 @@ "sideEffects": false, "type": "module", "types": "./index.d.ts", - "version": "0.14.2", + "version": "0.15.0-alpha.11", "main": "index.js", "dependencies": { "@babel/runtime": "^7.18.9", diff --git a/packages/util/src/common.ts b/packages/util/src/common.ts index 770bc23a..1bd2812a 100644 --- a/packages/util/src/common.ts +++ b/packages/util/src/common.ts @@ -1,6 +1,10 @@ import type { KeyringPair } from "@polkadot/keyring/types"; import { Keyring } from "@polkadot/keyring"; import BN from "bn.js"; +import type {AddressOrPair} from "@polkadot/api-base/types/submittable"; +import type {IKeyringPair, Signer} from "@polkadot/types/types"; +import {hexToU8a, isFunction, u8aToHex} from "@polkadot/util"; +import type {AccountId, Address} from "@polkadot/types/interfaces/runtime"; // interface assertLengthFunc { // (upper: number, lower: number): number @@ -44,6 +48,40 @@ export const unlockKeypair = (pair: PubKeyPinPair, keyring: Keyring): KeyringPai return keyPair; } +/** + * Slightly different from polkadot-js' approach, but we want to handle the same interface like they + * do. + * @param account + * @param payload + * @param signer + */ +export async function signPayload(account: AddressOrPair, payload: Uint8Array, signer?: Signer): Promise { + if (isKeyringPair(account)) { + return account.sign(payload); + } + + // console.log(`signer: ${JSON.stringify(signer)}`) + + if (signer === undefined) { + throw new Error('Invalid signer, either pass a Pair as account or a Signer.'); + } + + if (isFunction(signer.signRaw)) { + const address = asString(account); + const result = await signer.signRaw({address, type: "bytes", data: u8aToHex(payload) }); + return hexToU8a(result.signature); + } else { + throw new Error('Invalid signer interface, `signRaw` has to be defined.'); + } +} + +export function asString(addressOrPair: AddressOrPair): string { + return isKeyringPair(addressOrPair) ? addressOrPair.address : addressOrPair.toString(); +} + +export function isKeyringPair (account: string | IKeyringPair | AccountId | Address): account is IKeyringPair { + return isFunction((account as IKeyringPair).sign); +} /** * Our fixed point integer values go until I64, which means that it may be > 53 bits. diff --git a/packages/worker-api/package.json b/packages/worker-api/package.json index 06e1eae2..2e0cc98f 100644 --- a/packages/worker-api/package.json +++ b/packages/worker-api/package.json @@ -19,12 +19,12 @@ "sideEffects": false, "type": "module", "types": "./index.d.ts", - "version": "0.14.2", + "version": "0.15.0-alpha.11", "main": "index.js", "dependencies": { - "@encointer/node-api": "^0.14.2", - "@encointer/types": "^0.14.2", - "@encointer/util": "^0.14.2", + "@encointer/node-api": "^0.15.0-alpha.11", + "@encointer/types": "^0.15.0-alpha.11", + "@encointer/util": "^0.15.0-alpha.11", "@peculiar/webcrypto": "^1.4.6", "@polkadot/api": "^11.2.1", "@polkadot/keyring": "^12.6.2", diff --git a/packages/worker-api/src/encointerWorker.ts b/packages/worker-api/src/encointerWorker.ts index 9a6a2c3c..cdf0b47d 100644 --- a/packages/worker-api/src/encointerWorker.ts +++ b/packages/worker-api/src/encointerWorker.ts @@ -9,7 +9,7 @@ import type { Attestation, } from '@encointer/types'; -import {type CallOptions, Request} from './interface.js'; +import {type RequestOptions, Request} from './interface.js'; import {callGetter} from './sendRequest.js'; import {PubKeyPinPair, toAccount} from "@encointer/util/common"; import type {KeyringPair} from "@polkadot/keyring/types"; @@ -24,70 +24,70 @@ export class EncointerWorker extends Worker { return communityIdentifierFromString(this.registry(), cidStr); } - public async getNonce(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getNonce(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.TrustedGetter, 'nonce', 'u32'], { shard: cid, account: toAccount(accountOrPubKey, this.keyring()) }, options) } - public async getTotalIssuance(cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getTotalIssuance(cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.PublicGetter, 'total_issuance', 'Balance'], {cid}, options) } - public async getParticipantCount(cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getParticipantCount(cid: string, options: RequestOptions = {} as RequestOptions): Promise { return (await callGetter(this, [Request.PublicGetter, 'participant_count', 'u64'], {cid}, options)).toNumber() } - public async getMeetupCount(cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getMeetupCount(cid: string, options: RequestOptions = {} as RequestOptions): Promise { return (await callGetter(this, [Request.PublicGetter, 'meetup_count', 'u64'], {cid}, options)).toNumber() } - public async getCeremonyReward(cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getCeremonyReward(cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.PublicGetter, 'ceremony_reward', 'I64F64'], {cid}, options) } - public async getLocationTolerance(cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getLocationTolerance(cid: string, options: RequestOptions = {} as RequestOptions): Promise { return (await callGetter(this, [Request.PublicGetter, 'location_tolerance', 'u32'], {cid}, options)).toNumber() } - public async getTimeTolerance(cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getTimeTolerance(cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.PublicGetter, 'time_tolerance', 'Moment'], {cid}, options) } - public async getSchedulerState(cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getSchedulerState(cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.PublicGetter, 'scheduler_state', 'SchedulerState'], {cid}, options) } - public async getBalance(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getBalance(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.TrustedGetter, 'free_balance', 'Balance'], { shard: cid, account: toAccount(accountOrPubKey,this.keyring()) }, options) } - public async getParticipantIndex(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getParticipantIndex(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.TrustedGetter, 'participant_index', 'ParticipantIndexType'], { cid, account: toAccount(accountOrPubKey,this.keyring()) }, options) } - public async getMeetupIndex(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: CallOptions = {} as CallOptions): Promise { + public async getMeetupIndex(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.TrustedGetter, 'meetup_index', 'MeetupIndexType'], { cid, account: toAccount(accountOrPubKey,this.keyring()) }, options) } - public async getAttestations(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: CallOptions = {} as CallOptions): Promise> { + public async getAttestations(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: RequestOptions = {} as RequestOptions): Promise> { return await callGetter>(this, [Request.TrustedGetter, 'attestations', 'Vec'], { cid, account: toAccount(accountOrPubKey,this.keyring()) }, options) } - public async getMeetupRegistry(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: CallOptions = {} as CallOptions): Promise> { + public async getMeetupRegistry(accountOrPubKey: KeyringPair | PubKeyPinPair, cid: string, options: RequestOptions = {} as RequestOptions): Promise> { return await callGetter>(this, [Request.TrustedGetter, 'meetup_registry', 'Vec'], { cid, account: toAccount(accountOrPubKey, this.keyring()) diff --git a/packages/worker-api/src/integriteeWorker.spec.ts b/packages/worker-api/src/integriteeWorker.spec.ts index d7884e4e..2a62d8c7 100644 --- a/packages/worker-api/src/integriteeWorker.spec.ts +++ b/packages/worker-api/src/integriteeWorker.spec.ts @@ -1,6 +1,6 @@ import { Keyring } from '@polkadot/api'; import { cryptoWaitReady } from '@polkadot/util-crypto'; -import { localDockerNetwork } from './testUtils/networks.js'; +import { paseoNetwork} from './testUtils/networks.js'; import { IntegriteeWorker } from './integriteeWorker.js'; import WS from 'websocket'; import {type KeyringPair} from "@polkadot/keyring/types"; @@ -8,7 +8,7 @@ import {type KeyringPair} from "@polkadot/keyring/types"; const {w3cwebsocket: WebSocket} = WS; describe('worker', () => { - const network = localDockerNetwork(); + const network = paseoNetwork(); let keyring: Keyring; let worker: IntegriteeWorker; let alice: KeyringPair; @@ -64,6 +64,16 @@ describe('worker', () => { }); }); + describe('getBalanceGetter', () => { + it('should return value', async () => { + const getter = await worker.getBalanceGetter(charlie, network.mrenclave); + console.log(`BalanceGetter: ${JSON.stringify(getter)}`); + const result = await getter.send(); + console.log('getBalance toNumber:', result.toString(10)); + expect(result).toBeDefined(); + }); + }); + describe('getNonce', () => { it('should return value', async () => { const result = await worker.getNonce(alice, network.mrenclave); @@ -72,6 +82,16 @@ describe('worker', () => { }); }); + describe('getNonceGetter', () => { + it('should return value', async () => { + const getter = await worker.getNonceGetter(charlie, network.mrenclave); + console.log(`NonceGetter: ${JSON.stringify(getter)}`); + const result = await getter.send(); + console.log('getNonce', result); + expect(result).toBeDefined(); + }); + }); + describe('balance transfer should work', () => { it('should return value', async () => { const shard = network.chosenCid; diff --git a/packages/worker-api/src/integriteeWorker.ts b/packages/worker-api/src/integriteeWorker.ts index e4419944..efb7e666 100644 --- a/packages/worker-api/src/integriteeWorker.ts +++ b/packages/worker-api/src/integriteeWorker.ts @@ -1,72 +1,134 @@ import type {u32} from '@polkadot/types'; -import type {KeyringPair} from '@polkadot/keyring/types'; import type {Balance, Hash} from '@polkadot/types/interfaces/runtime'; import type { - ShardIdentifier, IntegriteeTrustedCallSigned, + ShardIdentifier, IntegriteeTrustedCallSigned, IntegriteeGetter, } from '@encointer/types'; - -import {type CallOptions, Request} from './interface.js'; -import {callGetter, sendTrustedCall} from './sendRequest.js'; -import {createTrustedCall} from "./requests.js"; -import {PubKeyPinPair, toAccount} from "@encointer/util/common"; +import { + type RequestOptions, + type ISubmittableGetter, + Request, + type JsonRpcRequest, type TrustedGetterArgs, type TrustedSignerOptions, +} from './interface.js'; import {Worker} from "./worker.js"; +import {callGetter, sendTrustedCall, sendWorkerRequest} from './sendRequest.js'; +import { + createGetterRpc, + createSignedGetter, + createTrustedCall, + signTrustedCall, +} from "./requests.js"; import bs58 from "bs58"; +import type {AddressOrPair} from "@polkadot/api-base/types/submittable"; export class IntegriteeWorker extends Worker { - public async getNonce(accountOrPubKey: KeyringPair | PubKeyPinPair, shard: string, options: CallOptions = {} as CallOptions): Promise { + public async getNonce(accountOrPubKey: AddressOrPair, shard: string, singerOptions?: TrustedSignerOptions, requestOptions?: RequestOptions): Promise { return await callGetter(this, [Request.TrustedGetter, 'nonce', 'u32'], { shard: shard, - account: toAccount(accountOrPubKey, this.keyring()) - }, options) + account: accountOrPubKey, + signer: singerOptions?.signer + }, requestOptions) + } + + public async getNonceGetter(accountOrPubKey: AddressOrPair, shard: string, signerOptions?: TrustedSignerOptions): Promise> { + const trustedGetterArgs = { + shard: shard, + account: accountOrPubKey, + signer: signerOptions?.signer, + } + return await submittableGetter(this, 'nonce', trustedGetterArgs,'u32'); } - public async getBalance(accountOrPubKey: KeyringPair | PubKeyPinPair, shard: string, options: CallOptions = {} as CallOptions): Promise { + public async getBalance(accountOrPubKey: AddressOrPair, shard: string, signerOptions?: TrustedSignerOptions, requestOptions?: RequestOptions): Promise { return await callGetter(this, [Request.TrustedGetter, 'free_balance', 'Balance'], { shard: shard, - account: toAccount(accountOrPubKey, this.keyring()) - }, options) + account: accountOrPubKey, + signer: signerOptions?.signer + }, requestOptions) + } + + public async getBalanceGetter(accountOrPubKey: AddressOrPair, shard: string, signerOptions?: TrustedSignerOptions): Promise> { + const trustedGetterArgs = { + shard: shard, + account: accountOrPubKey, + signer: signerOptions?.signer + } + return await submittableGetter(this, 'free_balance', trustedGetterArgs,'Balance'); } public async trustedBalanceTransfer( - accountOrPubKey: KeyringPair | PubKeyPinPair, + account: AddressOrPair, shard: string, mrenclave: string, from: String, to: String, amount: number, - options: CallOptions = {} as CallOptions + signerOptions?: TrustedSignerOptions, + requestOptions?: RequestOptions, ): Promise { - const nonce = await this.getNonce(accountOrPubKey, shard, options); + const nonce = signerOptions?.nonce ?? await this.getNonce(account, shard, signerOptions, requestOptions); const shardT = this.createType('ShardIdentifier', bs58.decode(shard)); const params = this.createType('BalanceTransferArgs', [from, to, amount]) - const call = createTrustedCall(this, ['balance_transfer', 'BalanceTransferArgs'], accountOrPubKey, shardT, mrenclave, nonce, params); - return this.sendTrustedCall(call, shardT, options); + const call = createTrustedCall(this, ['balance_transfer', 'BalanceTransferArgs'], params); + const signed = await signTrustedCall(this, call, account, shardT, mrenclave, nonce, signerOptions); + return this.sendTrustedCall(signed, shardT, requestOptions); } public async balanceUnshieldFunds( - accountOrPubKey: KeyringPair | PubKeyPinPair, + account: AddressOrPair, shard: string, mrenclave: string, fromIncognitoAddress: string, toPublicAddress: string, amount: number, - options: CallOptions = {} as CallOptions + signerOptions?: TrustedSignerOptions, + requestOptions?: RequestOptions, ): Promise { - const nonce = await this.getNonce(accountOrPubKey, shard, options); + const nonce = signerOptions?.nonce ?? await this.getNonce(account, shard, signerOptions, requestOptions); const shardT = this.createType('ShardIdentifier', bs58.decode(shard)); const params = this.createType('BalanceUnshieldArgs', [fromIncognitoAddress, toPublicAddress, amount, shardT]) - const call = createTrustedCall(this, ['balance_unshield', 'BalanceUnshieldArgs'], accountOrPubKey, shardT, mrenclave, nonce, params); - return this.sendTrustedCall(call, shardT, options); + const call = createTrustedCall(this, ['balance_unshield', 'BalanceUnshieldArgs'], params); + const signed = await signTrustedCall(this, call, account, shardT, mrenclave, nonce, signerOptions); + return this.sendTrustedCall(signed, shardT, requestOptions); } - async sendTrustedCall(call: IntegriteeTrustedCallSigned, shard: ShardIdentifier, options: CallOptions = {} as CallOptions): Promise { + async sendTrustedCall(call: IntegriteeTrustedCallSigned, shard: ShardIdentifier, requestOptions?: RequestOptions): Promise { if (this.shieldingKey() == undefined) { console.log(`[sentTrustedCall] Setting the shielding pubKey of the worker.`) - await this.getShieldingKey(options); + await this.getShieldingKey(requestOptions); } - return sendTrustedCall(this, call, shard, true, 'TrustedOperationResult', options); + return sendTrustedCall(this, call, shard, true, 'TrustedOperationResult', requestOptions); } } + +export class SubmittableGetter implements ISubmittableGetter { + worker: W; + shard: ShardIdentifier; + getter: IntegriteeGetter; + returnType: string; + + constructor(worker: W, shard: ShardIdentifier, getter: IntegriteeGetter, returnType: string) { + this.worker = worker; + this.shard = shard; + this.getter = getter; + this.returnType = returnType; + } + + into_rpc(): JsonRpcRequest { + return createGetterRpc(this.worker, this.getter, this.shard); + } + + send(requestOptions?: RequestOptions): Promise { + const rpc = this.into_rpc(); + return sendWorkerRequest(this.worker, rpc, this.returnType, requestOptions); + } +} + +export const submittableGetter = async (self: W, request: string, args: TrustedGetterArgs, returnType: string)=> { + const {shard, account} = args; + const shardT = self.createType('ShardIdentifier', bs58.decode(shard)); + const signedGetter = await createSignedGetter(self, request, account, { signer: args?.signer }) + return new SubmittableGetter(self, shardT, signedGetter, returnType); +} diff --git a/packages/worker-api/src/interface.ts b/packages/worker-api/src/interface.ts index 64af01e8..c6f9bc05 100644 --- a/packages/worker-api/src/interface.ts +++ b/packages/worker-api/src/interface.ts @@ -1,9 +1,11 @@ -import type { KeyringPair } from '@polkadot/keyring/types'; import WebSocketAsPromised from 'websocket-as-promised'; import {Keyring} from "@polkadot/keyring"; import type {u8} from "@polkadot/types-codec"; -import type {TypeRegistry, Vec} from "@polkadot/types"; -import type {RegistryTypes} from "@polkadot/types/types"; +import type {TypeRegistry, u32, Vec} from "@polkadot/types"; +import type {RegistryTypes, Signer} from "@polkadot/types/types"; +import type {AddressOrPair} from "@polkadot/api-base/types/submittable"; +import {Worker} from "./worker.js"; +import type {IntegriteeGetter, ShardIdentifier} from "@encointer/types"; export interface IWorker extends WebSocketAsPromised { rsCount: number; @@ -15,6 +17,21 @@ export interface IWorker extends WebSocketAsPromised { registry: () => TypeRegistry } +export interface ISubmittableGetter { + + worker: W; + + shard: ShardIdentifier; + + getter: IntegriteeGetter; + + returnType: string, + + into_rpc(): JsonRpcRequest; + + send(): Promise; +} + export interface JsonRpcRequest { jsonrpc: string; method: string; @@ -39,7 +56,21 @@ export interface WorkerOptions { export interface TrustedGetterArgs { shard: string; - account: KeyringPair; + account: AddressOrPair; + signer?: Signer +} + +/** + * Signer options. + * + * In the future, this might include other things. + */ +export interface TrustedSignerOptions { + // If this is null, we assume that the account is a Pair. + signer?: Signer; + + // If the nonce is null, it will be fetched. + nonce?: u32; } export interface PublicGetterArgs { @@ -48,7 +79,7 @@ export interface PublicGetterArgs { export type RequestArgs = PublicGetterArgs | TrustedGetterArgs | { } -export interface CallOptions { +export interface RequestOptions { timeout?: number; debug?: boolean; } diff --git a/packages/worker-api/src/requests.ts b/packages/worker-api/src/requests.ts index d452ea4f..21969b3c 100644 --- a/packages/worker-api/src/requests.ts +++ b/packages/worker-api/src/requests.ts @@ -1,62 +1,85 @@ import { createJsonRpcRequest, - type IWorker, type PublicGetterArgs, - type TrustedGetterArgs + type IWorker, + type PublicGetterArgs, + type TrustedGetterArgs, + type TrustedSignerOptions } from "./interface.js"; -import type {BalanceTransferArgs, BalanceUnshieldArgs, ShardIdentifier, IntegriteeTrustedCallSigned} from "@encointer/types"; -import type {KeyringPair} from "@polkadot/keyring/types"; -import {type PubKeyPinPair, toAccount} from "@encointer/util"; +import type { + BalanceTransferArgs, + BalanceUnshieldArgs, + IntegriteeGetter, + IntegriteeTrustedCall, + IntegriteeTrustedCallSigned, + IntegriteeTrustedGetter, + ShardIdentifier +} from "@encointer/types"; +import {asString, signPayload} from "@encointer/util"; import type {u32} from "@polkadot/types"; import bs58 from "bs58"; +import type {AddressOrPair} from "@polkadot/api-base/types/submittable"; // Todo: Properly resolve cid vs shard -export const clientRequestGetter = (self: IWorker, request: string, args: PublicGetterArgs) => { - const { cid } = args; +export const clientRequestGetterRpc = (self: IWorker, request: string, args: PublicGetterArgs) => { + const {cid} = args; const getter = self.createType('IntegriteePublicGetter', { [request]: cid }); - const g = self.createType( 'IntegriteeGetter',{ + const g = self.createType('IntegriteeGetter', { public: { getter, } }); + const shardT = self.createType('ShardIdentifier', bs58.decode(cid)); - const r = self.createType( - 'Request', { shard: cid, cyphertext: g.toU8a() } - ); - - return createJsonRpcRequest('state_executeGetter', [r.toHex()],1); + return createGetterRpc(self, g, shardT); } -export const clientRequestTrustedGetter = (self: IWorker, request: string, args: TrustedGetterArgs) => { +export const clientRequestTrustedGetterRpc = async (self: IWorker, request: string, args: TrustedGetterArgs) => { const {shard, account} = args; - const address = account.address; - const getter = self.createType('IntegriteeTrustedGetter', { + const shardT = self.createType('ShardIdentifier', bs58.decode(shard)); + const signedGetter = await createSignedGetter(self, request, account, {signer: args?.signer}); + return createGetterRpc(self, signedGetter, shardT); +} + +export const createSignedGetter = async (self: IWorker, request: string, account: AddressOrPair, options: TrustedSignerOptions) => { + const trustedGetter = createTrustedGetter(self, request, asString(account)); + return await signTrustedGetter(self, account, trustedGetter, options); +} + +export const createTrustedGetter = (self: IWorker, request: string, address: string) => { + return self.createType('IntegriteeTrustedGetter', { [request]: address }); +} - const signature = account.sign(getter.toU8a()); - const g = self.createType( 'IntegriteeGetter',{ +export async function signTrustedGetter(self: IWorker, account: AddressOrPair, getter: IntegriteeTrustedGetter, options?: TrustedSignerOptions): Promise { + const signature = await signPayload(account, getter.toU8a(), options?.signer); + const g = self.createType('IntegriteeGetter', { trusted: { getter, - signature: { Sr25519: signature }, + signature: {Sr25519: signature}, } }); - console.log(`TrustedGetter: ${JSON.stringify(g)}`); + // console.log(`TrustedGetter: ${JSON.stringify(g)}`); + // console.log(`TrustedGetter Encoded: ${g.toU8a()}`); + return g; +} - const s = self.createType('ShardIdentifier', bs58.decode(shard)); +export const createGetterRpc = (self: IWorker, getter: IntegriteeGetter, shard: ShardIdentifier) => { const r = self.createType( 'Request', { - shard: s, - cyphertext: g.toHex() + shard: shard, + cyphertext: getter.toHex() } ); - return createJsonRpcRequest('state_executeGetter', [r.toHex()],1); + return createJsonRpcRequest('state_executeGetter', [r.toHex()], 1); } + export type TrustedCallArgs = (BalanceTransferArgs | BalanceUnshieldArgs); export type TrustedCallVariant = [string, string] @@ -64,25 +87,33 @@ export type TrustedCallVariant = [string, string] export const createTrustedCall = ( self: IWorker, trustedCall: TrustedCallVariant, - accountOrPubKey: (KeyringPair | PubKeyPinPair), - shard: ShardIdentifier, - mrenclave: string, - nonce: u32, params: TrustedCallArgs -): IntegriteeTrustedCallSigned => { - +): IntegriteeTrustedCall => { const [variant, argType] = trustedCall; - const hash = self.createType('Hash', bs58.decode(mrenclave)); - const call = self.createType('IntegriteeTrustedCall', { + return self.createType('IntegriteeTrustedCall', { [variant]: self.createType(argType, params) }); +} + +export const signTrustedCall = async ( + self: IWorker, + call: IntegriteeTrustedCall, + account: AddressOrPair, + shard: ShardIdentifier, + mrenclave: string, + nonce: u32, + options?: TrustedSignerOptions, +): Promise => { + const hash = self.createType('Hash', bs58.decode(mrenclave)); const payload = Uint8Array.from([...call.toU8a(), ...nonce.toU8a(), ...hash.toU8a(), ...shard.toU8a()]); + const signature = await signPayload(account, payload, options?.signer); + return self.createType('IntegriteeTrustedCallSigned', { call: call, nonce: nonce, - signature: { Sr25519: toAccount(accountOrPubKey, self.keyring()).sign(payload) }, + signature: {Sr25519: signature}, }); } diff --git a/packages/worker-api/src/sendRequest.ts b/packages/worker-api/src/sendRequest.ts index 6f31ea95..1b926d09 100644 --- a/packages/worker-api/src/sendRequest.ts +++ b/packages/worker-api/src/sendRequest.ts @@ -3,58 +3,59 @@ import { type TrustedGetterArgs, type PublicGetterArgs, type RequestArgs, - type CallOptions, + type RequestOptions, type WorkerMethod, createJsonRpcRequest } from './interface.js'; import { Request } from './interface.js'; import { - clientRequestGetter, - clientRequestTrustedGetter, + clientRequestGetterRpc, + clientRequestTrustedGetterRpc, } from "./requests.js"; import type {ShardIdentifier, IntegriteeTrustedCallSigned} from "@encointer/types"; -const sendWorkerRequest = (self: IWorker, clientRequest: any, parserType: string, options: CallOptions): Promise =>{ +export const sendWorkerRequest = (self: IWorker, clientRequest: any, parserType: string, options?: RequestOptions): Promise =>{ const requestId = self.rqStack.push(parserType) + self.rsCount; + const timeout = options && options.timeout ? options.timeout : undefined; return self.sendRequest( clientRequest, { - timeout: options.timeout, + timeout: timeout, requestId } ) } -const sendTrustedGetterRequest = (self: IWorker, method: string, parser: string, args: TrustedGetterArgs, options: CallOptions) => - sendWorkerRequest(self, clientRequestTrustedGetter(self, method, args), parser, options) +const sendTrustedGetterRequest = async (self: IWorker, method: string, parser: string, args: TrustedGetterArgs, options?: RequestOptions) => + sendWorkerRequest(self, await clientRequestTrustedGetterRpc(self, method, args), parser, options) -const sendPublicGetterRequest = (self: IWorker, method: string, parser: string, args: PublicGetterArgs, options: CallOptions) => - sendWorkerRequest(self, clientRequestGetter(self, method, args), parser, options) +const sendPublicGetterRequest = (self: IWorker, method: string, parser: string, args: PublicGetterArgs, options?: RequestOptions) => + sendWorkerRequest(self, clientRequestGetterRpc(self, method, args), parser, options) -export const callGetter = async (self: IWorker, workerMethod: WorkerMethod, args: RequestArgs, options: CallOptions = {} as CallOptions): Promise => { +export const callGetter = async (self: IWorker, workerMethod: WorkerMethod, args: RequestArgs, requestOptions?: RequestOptions): Promise => { if( !self.isOpened ) { await self.open(); } const [getterType, method, parser] = workerMethod; let result: Promise; - let parserType: string = options.debug ? 'raw': parser; + let parserType: string = requestOptions?.debug ? 'raw': parser; switch (getterType) { case Request.TrustedGetter: - result = sendTrustedGetterRequest(self, method, parserType, args as TrustedGetterArgs, options) + result = sendTrustedGetterRequest(self, method, parserType, args as TrustedGetterArgs, requestOptions) break; case Request.PublicGetter: - result = sendPublicGetterRequest(self, method, parserType, args as PublicGetterArgs, options) + result = sendPublicGetterRequest(self, method, parserType, args as PublicGetterArgs, requestOptions) break; case Request.Worker: - result = sendWorkerRequest(self, createJsonRpcRequest(method, [], 1), parserType, options) + result = sendWorkerRequest(self, createJsonRpcRequest(method, [], 1), parserType, requestOptions) break; default: - result = sendPublicGetterRequest(self, method, parserType, args as PublicGetterArgs, options) + result = sendPublicGetterRequest(self, method, parserType, args as PublicGetterArgs, requestOptions) break; } return result as Promise } -export const sendTrustedCall = async (self: IWorker, call: IntegriteeTrustedCallSigned, shard: ShardIdentifier, direct: boolean, parser: string, options: CallOptions = {} as CallOptions): Promise => { +export const sendTrustedCall = async (self: IWorker, call: IntegriteeTrustedCallSigned, shard: ShardIdentifier, direct: boolean, parser: string, options: RequestOptions = {} as RequestOptions): Promise => { if( !self.isOpened ) { await self.open(); } diff --git a/packages/worker-api/src/testUtils/networks.ts b/packages/worker-api/src/testUtils/networks.ts index cd471590..a18308de 100644 --- a/packages/worker-api/src/testUtils/networks.ts +++ b/packages/worker-api/src/testUtils/networks.ts @@ -52,7 +52,7 @@ export const paseoNetwork = () => { // reverse proxy to the worker worker: 'wss://scv1.paseo.api.incognitee.io:443', genesisHash: '', - mrenclave: '7RuM6U4DLEtrTnVntDjDPBCAN4LbCGRpnmcTYUGhLqc7', + mrenclave: '5wePd1LYa5M49ghwgZXs55cepKbJKhj5xfzQGfPeMS7c', // abused as shard vault chosenCid: '5wePd1LYa5M49ghwgZXs55cepKbJKhj5xfzQGfPeMS7c', customTypes: {}, diff --git a/packages/worker-api/src/worker.ts b/packages/worker-api/src/worker.ts index 9bcf3100..cdbfd70d 100644 --- a/packages/worker-api/src/worker.ts +++ b/packages/worker-api/src/worker.ts @@ -11,7 +11,7 @@ import {parseI64F64} from '@encointer/util'; import type {Vault} from '@encointer/types'; -import {type CallOptions, type IWorker, Request, type WorkerOptions} from './interface.js'; +import {type RequestOptions, type IWorker, Request, type WorkerOptions} from './interface.js'; import {parseBalance} from './parsers.js'; import {callGetter} from './sendRequest.js'; import {encryptWithPublicKey, parseWebCryptoRSA} from "./webCryptoRSA.js"; @@ -153,13 +153,13 @@ export class Worker extends WebSocketAsPromised implements IWorker { this.#shieldingKey = shieldingKey; } - public async getShieldingKey(options: CallOptions = {} as CallOptions): Promise { + public async getShieldingKey(options: RequestOptions = {} as RequestOptions): Promise { const key = await callGetter(this, [Request.Worker, 'author_getShieldingKey', 'CryptoKey'], {}, options) this.setShieldingKey(key); return key; } - public async getShardVault(options: CallOptions = {} as CallOptions): Promise { + public async getShardVault(options: RequestOptions = {} as RequestOptions): Promise { return await callGetter(this, [Request.Worker, 'author_getShardVault', 'Vault'], {}, options) } } diff --git a/yarn.lock b/yarn.lock index a465262d..d2598cad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -755,18 +755,18 @@ __metadata: languageName: node linkType: hard -"@encointer/node-api@npm:^0.14.2, @encointer/node-api@workspace:packages/node-api": +"@encointer/node-api@npm:^0.15.0-alpha.11, @encointer/node-api@workspace:packages/node-api": version: 0.0.0-use.local resolution: "@encointer/node-api@workspace:packages/node-api" dependencies: - "@encointer/types": "npm:^0.14.2" + "@encointer/types": "npm:^0.15.0-alpha.11" "@polkadot/api": "npm:^11.2.1" "@polkadot/util-crypto": "npm:^12.6.2" tslib: "npm:^2.6.2" languageName: unknown linkType: soft -"@encointer/types@npm:^0.14.2, @encointer/types@workspace:packages/types": +"@encointer/types@npm:^0.15.0-alpha.11, @encointer/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@encointer/types@workspace:packages/types" dependencies: @@ -781,7 +781,7 @@ __metadata: languageName: unknown linkType: soft -"@encointer/util@npm:^0.14.2, @encointer/util@workspace:packages/util": +"@encointer/util@npm:^0.15.0-alpha.11, @encointer/util@workspace:packages/util": version: 0.0.0-use.local resolution: "@encointer/util@workspace:packages/util" dependencies: @@ -798,9 +798,9 @@ __metadata: version: 0.0.0-use.local resolution: "@encointer/worker-api@workspace:packages/worker-api" dependencies: - "@encointer/node-api": "npm:^0.14.2" - "@encointer/types": "npm:^0.14.2" - "@encointer/util": "npm:^0.14.2" + "@encointer/node-api": "npm:^0.15.0-alpha.11" + "@encointer/types": "npm:^0.15.0-alpha.11" + "@encointer/util": "npm:^0.15.0-alpha.11" "@peculiar/webcrypto": "npm:^1.4.6" "@polkadot/api": "npm:^11.2.1" "@polkadot/keyring": "npm:^12.6.2"