Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[experimental] Performance issue on sign-heavy workloads #1788

Closed
mcintyre94 opened this issue Oct 27, 2023 · 1 comment · Fixed by #1789
Closed

[experimental] Performance issue on sign-heavy workloads #1788

mcintyre94 opened this issue Oct 27, 2023 · 1 comment · Fixed by #1789
Labels
bug Something isn't working

Comments

@mcintyre94
Copy link
Collaborator

mcintyre94 commented Oct 27, 2023

Overview

I've been doing some performance testing of the new web3js on a sign-heavy workload. An example is create N signers, and then sign a transaction with all N signers M times.

At the extreme, there's a small performance regression between old web3js and new web3js:

Old:

Signed 100 transactions with 30 signers in 988 milliseconds
node index.mjs 30 100  1.38s user 0.07s system 106% cpu 1.361 total

New:

Signed 100 transactions with 30 signers in 1251 milliseconds
node index.mjs 30 100  1.73s user 0.07s system 103% cpu 1.735 total

(the time in the first line is just the signing (measured with performance.now inside the script), the second line is the output of time when running the script, so it has a longer total time since it includes eg generating the keypairs)

With fewer signers, we're faster:

Old:

Signed 100 transactions with 5 signers in 184 milliseconds
node index.mjs 5 100  0.50s user 0.03s system 75% cpu 0.712 total

New:

Signed 100 transactions with 5 signers in 89 milliseconds
node index.mjs 5 100  0.33s user 0.04s system 44% cpu 0.804 total

This made me suspect that there's a performance issue in our logic for signing. It shouldn't take >10x longer to sign with 6x more signers per transaction.

The issue is here:

const publicKeySignaturePairs = await Promise.all(
keyPairs.map(keyPair =>
Promise.all([
getAddressFromPublicKey(keyPair.publicKey),
getCompiledMessageSignature(compiledMessage, keyPair.privateKey),
])
)
);

For each keypair, we are calling getAddressFromPublicKey(keyPair.publicKey) and getCompiledMessageSignature(compiledMessage, keyPair.privateKey)

In getCompiledMessageSignature we encode the message:

async function getCompiledMessageSignature(message: CompiledMessage, secretKey: CryptoKey) {
const wireMessageBytes = getCompiledMessageEncoder().encode(message);
const signature = await signBytes(secretKey, wireMessageBytes);
return signature;
}

This is the issue: we're re-encoding the transaction message for every signer every loop.

If we modify this to call the getCompiledMessageEncoder().encode(message) in signTransaction only once, we see a massive performance improvement:

Signed 100 transactions with 30 signers in 120 milliseconds
node index.mjs 30 100  0.48s user 0.08s system 77% cpu 0.720 total
Signed 100 transactions with 5 signers in 44 milliseconds
node index.mjs 5 100  0.25s user 0.03s system 38% cpu 0.747 total

TLDR: We should refactor so that when you call signTransaction the getCompiledMessageEncoder().encode(message) call is only made once. This will unlock a massive performance improvement for sign-heavy workloads.

Copy link
Contributor

github-actions bot commented Nov 6, 2023

Because there has been no activity on this issue for 7 days since it was closed, it has been automatically locked. Please open a new issue if it requires a follow up.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 6, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
1 participant