One idea for improving Penumbra sync speeds in the future is to implement some version of “DAGSync”, which is the idea that clients can walk the DAG of their transaction graph to scan faster.
In DAGSync, once a client detects a single transaction relevant to them, they can observe all of its outputs and check if each output note is unspent. If the output note is spent, they can learn which transaction spent it, and repeat the process, quickly traversing their own transaction history to reach a subset of notes that are still live.
However, Penumbra (and Zcash) only allow traversing the user’s transaction graph in one direction. The reason is that Spend
actions only reveal the nullifier of the note they spend, and there is (by design) no way to go “backwards” from the nullifier to the note commitment or the note itself.
This limits the effectiveness of DAGSync, because it means that the choice of the “seed note/tx” has large impacts on how much of the user’s history can be discovered. One mitigation is the idea of “knitting”, prioritizing newly received notes for spending in order to “knit” them into the graph and make their discovery unimportant, but this has other downsides – it makes it easier for attackers to tag activity (e.g., sending many new small notes, which would be prioritized for spending, causing a detectably high-arity transaction), and it doesn’t really solve the user need of wanting to find their complete transaction history.
Instead, if the Spend
action were augmented with a new field, backref_commitment
, like so:
message SpendBody {
// A commitment to the value of the input note.
penumbra.core.asset.v1.BalanceCommitment balance_commitment = 1;
// The nullifier of the input note.
penumbra.core.component.sct.v1.Nullifier nullifier = 6;
// The randomized validating key for the spend authorization signature.
penumbra.crypto.decaf377_rdsa.v1.SpendVerificationKey rk = 4;
// NEW: An encryption of the commitment of the input note to the sender's OVK.
bytes backref_commitment = 7;
}
Then a client could traverse their transaction graph forwards instead of backwards. This would allow searching for a “seed note/tx” starting from newest rather than oldest, and allow finding more branches of the tree without needing to perform knitting.
This field would not be checked by any consensus logic, so a client wishing to have forward secrecy can fill in invalid data. (I don’t think the default clients should support this behavior, but it’s important to be clear about this).
If this change were to be made, it would be good to make it as soon as possible, because it only allows accelerated sync for transactions after it lands. Because Penumbra still has very few users, there are not yet that many transactions, so now would be the second-best time to add this field (the best time having been prior to mainnet).
Questions:
- Should the backreference be the note commitment, or the transaction hash of the transaction that created the note?
- My initial preference would be the note commitment, since it’s more self-contained – there’s no extra data needed to be plumbed in. There might be a slight increase in RPC calls needed by the client (first looking up a txid by commitment and then fetching the tx) but this seems pretty unimportant or fixable at the RPC level.
- Should the field be optional, to allow a phased adoption period, or required, so that all transactions are indistinguishable?
- My initial preference would be a phased adoption period, making it optional initially and then required later, to minimize breakage of client software.
- Should the field be part of the effect hash?
- If not, what are the security effects?
- If so, what is needed to ensure adding the field to the effect hash doesn’t break anything (in case of a phased adoption / optional field)?