-
Notifications
You must be signed in to change notification settings - Fork 772
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
Client/Monorepo: Use WASM Crypto (keccak256) for Hashing / Consistent Hash Function Overwrite #3192
Conversation
Codecov ReportAttention:
Additional details and impacted files
Flags with carried forward coverage won't be shown. Click here to find out more. |
b9a8f0b
to
159abd1
Compare
I'm liking this new approach. I wonder if we should do the same with KZG and move away from the global singleton |
@@ -93,6 +96,8 @@ export class Trie { | |||
throw new Error('`valueEncoding` can only be set if a `db` is provided') | |||
} | |||
this._opts = { ...this._opts, ...opts } | |||
this._opts.useKeyHashingFunction = | |||
opts.common?.customCrypto.keccak256 ?? opts.useKeyHashingFunction ?? keccak256 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just remember that recently in an exchange with @jochem-brouwer we stumbled upon a problem (unexpected evaluation) when using this kind of operator chaining, can't completely recall the constallation specifics though. 🤔
Did some basic tests and these went as expected:
So just dropping this here for awareness.
(maybe though it was something with the ?
operator from TypeScript? So a problem might occur when - in the case above - common
is not defined? Maybe things would then not evaluate properly? Not sure if Jochem can give more insight here (If I recall correctly a solution for our problem were adding some brackets)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't recall the specifics, do you maybe have some more context when we stumbled upon this? I do slightly remember a "gotcha" with these operators though, but I don't recall in which context 😅
if (Object.isFrozen(tx)) { | ||
if (!tx.cache.hash) { | ||
tx.cache.hash = keccak256(tx.serialize()) | ||
tx.cache.hash = keccackFunction(tx.serialize()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really happy here that our capability consolidation in tx is already paying off. 🤩
//cc @gabrocheleau
Just compiling a list here on what is still missing, in case its helpful (no matter who continues on this):
And finally, tricky one but I guess important: Ugh. This list went longer than I expected. 😆 🙂 But on the other hand: if WASM is really that much faster this also REALLY will have an impact if applied so broadly! (and on the good/relieving side: most changes really shouldn't be invasive (at all), now with the alternatives to the original methods mostly at hand. We likely (sigh) should add some minimal level of additional testing though, also on the per-library level) |
* Devp2p: add keccak function and Common passing structure to RLPx, DPT, DNS * Client: pass in common along devp2p DPT instantiation * Devp2p: expand to ECIES, first replacement test * Devp2p: First full-round replacement (including concatBytes occurrences) for ECIES * Devp2p: integrate into DPT server and message * Devp2p: Add to DNS ENR * Devp2p: remove util keccak256 helper function
…-wasm-lib-hashing
…-wasm-lib-hashing
Updated this via UI. @acolytec3 feel free to merge this in whenever you think it’s ready! |
(from my side additional commits look good) |
@@ -828,6 +890,8 @@ async function run() { | |||
chain: chainName, | |||
mergeForkIdPostMerge: args.mergeForkIdPostMerge, | |||
}) | |||
//@ts-ignore | |||
common.customCrypto = cryptoFunctions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: should likely add this customCrypto
to the fromGethGenesis
constructor also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Maybe the next PR.
@@ -50,6 +51,8 @@ export class RLPx { | |||
protected _refillIntervalId: NodeJS.Timeout | |||
protected _refillIntervalSelectionCounter: number = 0 | |||
|
|||
protected _keccakFunction: (msg: Uint8Array) => Uint8Array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, why is this added? It's used nowhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, but I'll sure use it in future devp2p PRs.
let key = ROOT_DB_KEY | ||
|
||
const encoding = | ||
opts?.valueEncoding === ValueEncoding.Bytes ? ValueEncoding.Bytes : ValueEncoding.String | ||
|
||
if (opts?.useKeyHashing === true) { | ||
key = (opts?.useKeyHashingFunction ?? keccak256)(ROOT_DB_KEY) as Uint8Array | ||
key = keccakFunction.call(undefined, ROOT_DB_KEY) as Uint8Array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, why do we have to .call
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤷 I think this was left over from when @holgerd77 was trying to introduce a global crypto thing or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few nits, ready to merge once CI passes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving this. @jochem-brouwer or @holgerd77, this can be merged if everyone is satisfied. Plenty of work to add in future PRs but I think this one is fine as is.
I'm fine to merge this when CI passes :) |
👍 |
This was actually the original triggger for #3187, hehe. 😁
So this PR tests the @polkadot/wasm-crypto library as a replacement for the trie key hashing for the VM state manager in the client. Had this long on my plate to analyse this a bit better, since theoretically (re-)using a more native hash function should have a significant performance imact.
So I tested with the following early mainnet block (now starting directly with the block to avoid state caches):
Block has 79 simple value transfer txs, so not much else is happening and mainly the sender and receiver state changes are written and come into play here.
Following results (with just the first two commits, so only exchanging for trie in execution):
Before (Entire Block): 280ms 277ms 276ms 283ms. 285ms 283ms. 280ms. 279ms
After. (Entire Block): 264ms. 270ms. 265ms. 268ms. 266ms. 262ms. 263ms. 265ms
Results are significant enough that I would continue here, especially since these are results for only exchanging things for the execution state trie, I expect this to get even substantially further if we do this holistically and exchange for all other places where keccak256 hashing is applied (tx trie validations, keccak256 precompile + opcode (there are these two, right?), guess some other things as well).
I will work a bit on this since I would like to get this done in a clean way. If I am not mistaken our whole "replace the hash function" functionality/API is generally not complete (so pretty sure e.g. for VM this is neither possible in the precompile or anywhere + things (the changed hash function) would at the end also needed to passed down to the lower level libraries.