4
1
mirror of https://github.com/Qortal/qortal-ui.git synced 2025-02-15 19:55:49 +00:00

put computePow into web workers

This commit is contained in:
Phillip Lang Martinez 2022-11-07 23:10:17 +02:00
parent e6dfa5dc35
commit cde4de4a15
6 changed files with 254 additions and 66 deletions

View File

@ -8,6 +8,8 @@ const commonjs = require('@rollup/plugin-commonjs');
const alias = require('@rollup/plugin-alias'); const alias = require('@rollup/plugin-alias');
const { terser } = require('rollup-plugin-terser'); const { terser } = require('rollup-plugin-terser');
const babel = require('@rollup/plugin-babel'); const babel = require('@rollup/plugin-babel');
const webWorkerLoader = require('rollup-plugin-web-worker-loader');
const aliases = {}; const aliases = {};
@ -40,6 +42,7 @@ const generateRollupConfig = (inputFile, outputFile) => {
commonjs(), commonjs(),
globals(), globals(),
progress(), progress(),
webWorkerLoader(),
babel.babel({ babel.babel({
babelHelpers: 'bundled', babelHelpers: 'bundled',
exclude: 'node_modules/**', exclude: 'node_modules/**',

View File

@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"@material/mwc-list": "0.27.0", "@material/mwc-list": "0.27.0",
"@material/mwc-select": "0.27.0", "@material/mwc-select": "0.27.0",
"asmcrypto.js": "2.3.2",
"compressorjs": "^1.1.1", "compressorjs": "^1.1.1",
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js", "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js",
"localforage": "^1.10.0", "localforage": "^1.10.0",
@ -60,7 +61,8 @@
"rollup": "2.79.1", "rollup": "2.79.1",
"rollup-plugin-node-globals": "1.4.0", "rollup-plugin-node-globals": "1.4.0",
"rollup-plugin-progress": "1.1.2", "rollup-plugin-progress": "1.1.2",
"rollup-plugin-terser": "7.0.2" "rollup-plugin-terser": "7.0.2",
"rollup-plugin-web-worker-loader": "^1.6.1"
}, },
"engines": { "engines": {
"node": ">=16.15.0" "node": ">=16.15.0"

View File

@ -21,7 +21,10 @@ import '@material/mwc-dialog'
import '@material/mwc-icon' import '@material/mwc-icon'
import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js'; import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js';
import { publishData } from '../../utils/publish-image.js'; import { publishData } from '../../utils/publish-image.js';
import WebWorker from 'web-worker:./computePowWorker.js';
import WebWorkerImage from 'web-worker:./computePowWorkerImage.js';
// hello
const messagesCache = localForage.createInstance({ const messagesCache = localForage.createInstance({
name: "messages-cache", name: "messages-cache",
}); });
@ -1221,10 +1224,14 @@ class ChatPage extends LitElement {
parentEpml, parentEpml,
metaData: undefined, metaData: undefined,
uploadType: 'file', uploadType: 'file',
selectedAddress: this.selectedAddress selectedAddress: this.selectedAddress,
worker: new WebWorkerImage()
}) })
} catch (error) { } catch (error) {
console.error(error) console.error(error)
this.isLoading = false;
this.chatEditor.enable();
return
} }
@ -1291,17 +1298,25 @@ class ChatPage extends LitElement {
return return
} }
console.log({userName, identifier }) console.log({userName, identifier })
try {
await publishData({ await publishData({
registeredName: userName, registeredName: userName,
file : compressedFile, file : compressedFile,
service: 'IMAGE', service: 'IMAGE',
identifier : identifier, identifier : identifier,
parentEpml, parentEpml,
metaData: undefined, metaData: undefined,
uploadType: 'file', uploadType: 'file',
selectedAddress: this.selectedAddress selectedAddress: this.selectedAddress,
}) worker: new WebWorkerImage()
})
} catch (error) {
console.error(error)
this.isLoading = false;
this.chatEditor.enable();
return
}
const messageObject = { const messageObject = {
messageText: outSideMsg.caption, messageText: outSideMsg.caption,
images: [{ images: [{
@ -1477,23 +1492,33 @@ class ChatPage extends LitElement {
}; };
const _computePow = async (chatBytes) => { const _computePow = async (chatBytes) => {
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
const chatBytesArray = new Uint8Array(_chatBytesArray);
const chatBytesHash = new window.parent.Sha256().process(chatBytesArray).finish().result;
const hashPtr = window.parent.sbrk(32, window.parent.heap);
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
hashAry.set(chatBytesHash);
const difficulty = this.balance === 0 ? 12 : 8; const difficulty = this.balance === 0 ? 12 : 8;
const workBufferLength = 8 * 1024 * 1024; const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap); const worker = new WebWorker();
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty); let nonce = null
let chatBytesArray = null
await new Promise((res, rej) => {
console.log({chatBytes})
worker.postMessage({chatBytes, path, difficulty});
worker.onmessage = e => {
worker.terminate()
chatBytesArray = e.data.chatBytesArray
nonce = e.data.nonce
res()
}
})
let _response = await parentEpml.request('sign_chat', { let _response = await parentEpml.request('sign_chat', {
nonce: this.selectedAddress.nonce, nonce: this.selectedAddress.nonce,
chatBytesArray: chatBytesArray, chatBytesArray: chatBytesArray,
chatNonce: nonce chatNonce: nonce
}); });
getSendChatResponse(_response); getSendChatResponse(_response);
}; };

View File

@ -0,0 +1,83 @@
import { Sha256 } from 'asmcrypto.js'
function sbrk(size, heap){
let brk = 512 * 1024 // stack top
let old = brk
brk += size
if (brk > heap.length)
throw new Error('heap exhausted')
return old
}
self.addEventListener('message', async e => {
console.log({data: e.data})
const response = await computePow(e.data.chatBytes, e.data.path, e.data.difficulty)
postMessage(response)
})
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
const heap = new Uint8Array(memory.buffer)
const computePow = async (chatBytes, path, difficulty) => {
let response = null
await new Promise((resolve, reject)=> {
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
const chatBytesArray = new Uint8Array(_chatBytesArray);
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result;
const hashPtr = sbrk(32, heap);
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32);
hashAry.set(chatBytesHash);
const workBufferLength = 8 * 1024 * 1024;
const workBufferPtr = sbrk(workBufferLength, heap);
const importObject = {
env: {
memory: memory
},
};
function loadWebAssembly(filename, imports) {
// Fetch the file and compile it
return fetch(filename)
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
// Create the instance.
return new WebAssembly.Instance(module, importObject);
});
}
loadWebAssembly(path)
.then(wasmModule => {
response = {
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
chatBytesArray
}
resolve()
});
})
return response
}

View File

@ -0,0 +1,93 @@
import { Sha256 } from 'asmcrypto.js'
function sbrk(size, heap){
let brk = 512 * 1024 // stack top
let old = brk
brk += size
if (brk > heap.length)
throw new Error('heap exhausted')
return old
}
self.addEventListener('message', async e => {
console.log({data: e.data})
const response = await computePow(e.data.convertedBytes, e.data.path)
postMessage(response)
})
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
const heap = new Uint8Array(memory.buffer)
const computePow = async (convertedBytes, path) => {
let response = null
await new Promise((resolve, reject)=> {
const _convertedBytesArray = Object.keys(convertedBytes).map(
function (key) {
return convertedBytes[key]
}
)
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
const convertedBytesHash = new Sha256()
.process(convertedBytesArray)
.finish().result
const hashPtr = sbrk(32, heap)
const hashAry = new Uint8Array(
memory.buffer,
hashPtr,
32
)
hashAry.set(convertedBytesHash)
const difficulty = 14
const workBufferLength = 8 * 1024 * 1024
const workBufferPtr = sbrk(
workBufferLength,
heap
)
const importObject = {
env: {
memory: memory
},
};
function loadWebAssembly(filename, imports) {
return fetch(filename)
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
return new WebAssembly.Instance(module, importObject);
});
}
console.log({path})
loadWebAssembly(path)
.then(wasmModule => {
response = {
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
}
resolve()
});
})
return response
}

View File

@ -14,9 +14,9 @@ export const publishData = async ({
service, service,
identifier, identifier,
parentEpml, parentEpml,
metaData,
uploadType, uploadType,
selectedAddress, selectedAddress,
worker
}) => { }) => {
const validateName = async (receiverName) => { const validateName = async (receiverName) => {
let nameRes = await parentEpml.request("apiCall", { let nameRes = await parentEpml.request("apiCall", {
@ -47,35 +47,23 @@ export const publishData = async ({
const convertedBytes = const convertedBytes =
window.parent.Base58.decode(convertedBytesBase58) window.parent.Base58.decode(convertedBytesBase58)
const _convertedBytesArray = Object.keys(convertedBytes).map( let nonce = null
function (key) { const computPath =window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
return convertedBytes[key] await new Promise((res, rej) => {
}
) worker.postMessage({convertedBytes, path: computPath});
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
const convertedBytesHash = new window.parent.Sha256() worker.onmessage = e => {
.process(convertedBytesArray)
.finish().result worker.terminate()
const hashPtr = window.parent.sbrk(32, window.parent.heap)
const hashAry = new Uint8Array( nonce = e.data.nonce
window.parent.memory.buffer, res()
hashPtr,
32 }
) })
hashAry.set(convertedBytesHash)
const difficulty = 14
const workBufferLength = 8 * 1024 * 1024
const workBufferPtr = window.parent.sbrk(
workBufferLength,
window.parent.heap
)
let nonce = window.parent.computePow(
hashPtr,
workBufferPtr,
workBufferLength,
difficulty
)
let response = await parentEpml.request("sign_arbitrary", { let response = await parentEpml.request("sign_arbitrary", {
nonce: selectedAddress.nonce, nonce: selectedAddress.nonce,
arbitraryBytesBase58: transactionBytesBase58, arbitraryBytesBase58: transactionBytesBase58,
@ -131,18 +119,7 @@ export const publishData = async ({
postBody = Buffer.from(fileBuffer).toString("base64") postBody = Buffer.from(fileBuffer).toString("base64")
} }
// Optional metadata
// let title = encodeURIComponent(metaData.title || "")
// let description = encodeURIComponent(metaData.description || "")
// let category = encodeURIComponent(metaData.category || "")
// let tag1 = encodeURIComponent(metaData.tag1 || "")
// let tag2 = encodeURIComponent(metaData.tag2 || "")
// let tag3 = encodeURIComponent(metaData.tag3 || "")
// let tag4 = encodeURIComponent(metaData.tag4 || "")
// let tag5 = encodeURIComponent(metaData.tag5 || "")
// let metadataQueryString = `title=${title}&description=${description}&category=${category}&tags=${tag1}&tags=${tag2}&tags=${tag3}&tags=${tag4}&tags=${tag5}`
let uploadDataUrl = `/arbitrary/${service}/${registeredName}${urlSuffix}?apiKey=${getApiKey()}` let uploadDataUrl = `/arbitrary/${service}/${registeredName}${urlSuffix}?apiKey=${getApiKey()}`
if (identifier != null && identifier.trim().length > 0) { if (identifier != null && identifier.trim().length > 0) {
@ -162,5 +139,10 @@ export const publishData = async ({
} }
await validate() try {
await validate()
} catch (error) {
throw new Error(error.message)
}
} }