Skip to content

Modify Verification_key_wire handling so the daemon isn't forced to hash zkApp vks when deserializing accounts #18196

@cjjdespres

Description

@cjjdespres

The Verification_key_wire type is used in the definition of zkapp accounts. It has this binable definition:

(* don't send hash over the wire; restore hash on receipt *)
let to_binable (t : t) = t.data
let of_binable vk : t =
let data = vk in
let hash = digest_vk vk in
{ data; hash }

This forces the daemon to re-hash the verification key every time it wants to deserialize a verification key.

I believe this is part of the issue identified in #17501 - you can see in the backtrace of that issue that the daemon was recomputing the VK hash of a zkApp account when I took that backtrace. This does at least confirm that when we foldi over all the accounts in the mask like we do here:

let display_attached_mask mask =
let root_hash = Mask.Attached.merkle_root mask in
let num_accounts = Mask.Attached.num_accounts mask in
let total_currency =
Mask.Attached.foldi mask ~init:0 ~f:(fun _ total_currency account ->
(* only default token matters for total currency *)
if Token_id.equal (Account.token account) Token_id.default then
total_currency + (Balance.to_int @@ Account.balance account)
else total_currency )
in

that we do in fact need to re-hash the VK when we read the account from the database. (I think if the account is encountered in a mask first then it'll just use that and not touch the database, but there will generally not be many accounts in the masks, especially compared to the root database itself).

This will affect anything that folds (or even reads) from the ledger database but does not care about the verification key hash. I'm not sure if this happens all that often - ledger operations tend to be pretty incremental. Also this operation is still relatively fast - total ledger iteration time for devnet is only a few seconds (depending on hardware). The reason why it's such a big deal in #17501 is that the visualization will foldi over every mask in the transition frontier to compute the total_currency of the mask, which ends up needing a ~full ledger re-read each time, so that's at least ~290x more time for a daemon that's synced to the network.


Anyway, to solve this we might consider having a more basic Verification_key_wire.t type that has a unit hash instead of the current mandatory full hash. This would be the "Stable" version. The regular version would have the hash in it too. Then we would at least have the option of deserializing an account without being forced to recompute this hash. I'm unsure how much work this might take.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions