-
Notifications
You must be signed in to change notification settings - Fork 35
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
SMT should use Option<T>
#289
Comments
We specifically chose not to return an |
I disagree this is the semantics of the tree. It is true the sparse tree behaves as if the leaves existed, but that has to do with how the tree is encoded in memory. How the tree is encoded does not affect the interpretation of the leaf value. To my interpretation the value The above works because of hash collision resistance. We can assume it is extremely unlikely the result of a hash be same as |
I'm not sure I agree. Semantically, an empty SMT is identically to a fully balanced Merkle tree where every leaf is a "default value". In our case, the default value is |
I agree that
This is what I'm pointing out, "up to the user" means: let smt = SimpleSmt::new();
let value = smt.get_leaf(leaf(4));
if value == SimpleSmt::EMPTY_VALUE { // <-- this is leaking
// treat it as default or none
} A better API would be to have: let smt = SimpleSmt::new();
let value: Option<T> = smt.get_leaf(leaf(4)); // thumbstone represents `None`
// `None` is constructed internally and if we need, we can also have: let smt = SimpleSmt::new();
let value: T = smt.get_leaf(leaf(4)); // thumbstone represents the default value
// `T::default()` is called internally we can probably support both use cases by making |
How I'm reconciling both points of view is:
I agree with Augusto that returning IMO then for this API to be clean, we'd need to:
FWIW, Penumbra's Jellyfish merkle tree's |
I think the complication here is that we need work with |
I would think of Hence, we can have |
@plafer I didn't want to add explicit presence tracking, I think we already have what we need. At least for how the sparse Merkle tree is used for the nullifiers, we have the following:
The point I'm trying to make is that the interpretation of the thumbstone value Edit: To clarify the above, because I'm not 100% if I'm misinterpreting what you said. The main difference is that the api would be This bit of code should satisfy the things brought up in this discussion:
/// Represents objects that can be hashed
trait Hashable {
fn hash(&self) -> Digest;
}
/// Interface of a Merklelized map.
trait MerkleMap<K: Hashable, V: Hashable>
{
type Error;
type MerklePath;
fn root(&self) -> Digest;
fn insert(&mut self, key: K, value: V) -> Option<V>;
fn remove(&mut self, key: impl AsRef<K>) -> Result<V, Error>;
fn lookup(&self, key: impl AsRef<K>) -> Result<&V, Error>;
fn open(&self, key: impl AsRef<K>) -> Result<MerklePath, Error>;
}
/// A sparse implementation of a Merkle map.
///
/// This structure uses the default value of `hash(V::default())` as a thumbstone,
/// these entries are not stored in memory, saving space.
struct SparseMerkleMap { ... }
impl<K, V> MerkleTree<K, V> for SparseMerkleTree
where
K: Hashable,
V: Default + Hashable,
{
type Error = Infallible;
...
}
impl Hashable for Option<T: Hashable> {
fn hash(&self) -> Digest {
return EMPTY_WORD;
}
}
#[test]
fn usage() {
// support default values as mentioned by bobbin
let mut tree = SparseMerkleTree<Felt, Felt>::new();
assert_eq!(tree.get(ONE), Ok(ZERO)); // sparse tree prepopulated with the default
assert_eq!(tree.insert(ONE, ONE), Some(ZERO)); // same
// supports None as mentioned by me
let mut tree = SparseMerkleTree<Felt, Option<Felt>>::new();
assert_eq!(tree.get(ONE), Ok(None)); // the default is `None`
assert_eq!(tree.insert(ONE), Some(None)); // double wrapping :(
} The methods are fallible in the trait, but infallible in the example above by setting the I'm not sure if it is worth it though, unless we think this trait would be also used by users down the road. Otherwise I would use a simpler version, and if we really need add the tracking version later on. |
The
EMPTY_VALUE
is leaking in the API. And the users of the API now have to special case that, sometimes converting toOption<T>
themselves. It would make for a nicer API ifSmt
handled that directly.The text was updated successfully, but these errors were encountered: