diff --git a/src/hevm/src/EVM/Patricia.hs b/src/hevm/src/EVM/Patricia.hs index 6a60f694c..f19661f72 100644 --- a/src/hevm/src/EVM/Patricia.hs +++ b/src/hevm/src/EVM/Patricia.hs @@ -62,9 +62,11 @@ data Node = Empty -- the function HP from Appendix C of yellow paper encodePath :: Path -> Bool -> ByteString -encodePath p isTerminal | even (length p) = packNibbles $ Nibble flag : Nibble 0 : p - | otherwise = packNibbles $ Nibble (flag + 1) : p - where flag = if isTerminal then 2 else 0 +encodePath p isTerminal | even (length p) + = packNibbles $ Nibble flag : Nibble 0 : p + | otherwise + = packNibbles $ Nibble (flag + 1) : p + where flag = if isTerminal then 2 else 0 rlpRef :: Ref -> RLP rlpRef (Hash d) = BS d @@ -100,10 +102,12 @@ lookupPath root path = getNode root >>= getVal path getVal :: Path -> Node -> NodeDB ByteString getVal _ Empty = return BS.empty -getVal path (Shortcut nodePath ref) = case (stripPrefix nodePath path, ref) of - (Just [], Right value) -> return value - (Just remaining, Left key) -> lookupPath key remaining - _ -> return BS.empty +getVal path (Shortcut nodePath ref) = + case (stripPrefix nodePath path, ref) of + (Just [], Right value) -> return value + (Just remaining, Left key) -> lookupPath key remaining + _ -> return BS.empty + getVal [] (Full _ val) = return val getVal (p:ps) (Full refs _) = lookupPath (refs `Seq.index` (num p)) ps @@ -129,24 +133,32 @@ insertRef ref p val = do root <- getNode ref update :: Node -> Path -> ByteString -> NodeDB Node update Empty p new = return $ Shortcut p (Right new) update (Full refs _) [] new = return (Full refs new) -update (Full refs old) (p:ps) new = do newRef <- insertRef (refs `Seq.index` (num p)) ps new - return $ Full (Seq.update (num p) newRef refs) old -update (Shortcut (o:os) (Right old)) [] new = do newRef <- insertRef emptyRef os old - return $ Full (Seq.update (num o) newRef emptyRefs) new -update (Shortcut [] (Right old)) (p:ps) new = do newRef <- insertRef emptyRef ps new - return $ Full (Seq.update (num p) newRef emptyRefs) old -update (Shortcut [] (Right _)) [] new = return $ Shortcut [] (Right new) -update (Shortcut (o:os) to) (p:ps) new | o == p = update (Shortcut os to) ps new >>= addPrefix [o] - | otherwise = do oldRef <- case to of - (Left ref) -> getNode ref >>= addPrefix os >>= putNode - (Right val) -> insertRef emptyRef os val - newRef <- insertRef emptyRef ps new - let refs = Seq.update (num p) newRef $ Seq.update (num o) oldRef emptyRefs - return $ Full refs BS.empty -update (Shortcut (o:os) (Left ref)) [] new = do newRef <- getNode ref >>= addPrefix os >>= putNode - return $ Full (Seq.update (num o) newRef emptyRefs) new -update (Shortcut cut (Left ref)) ps new = do newRef <- insertRef ref ps new - return $ Shortcut cut (Left newRef) +update (Full refs old) (p:ps) new = do + newRef <- insertRef (refs `Seq.index` (num p)) ps new + return $ Full (Seq.update (num p) newRef refs) old +update (Shortcut (o:os) (Right old)) [] new = do + newRef <- insertRef emptyRef os old + return $ Full (Seq.update (num o) newRef emptyRefs) new +update (Shortcut [] (Right old)) (p:ps) new = do + newRef <- insertRef emptyRef ps new + return $ Full (Seq.update (num p) newRef emptyRefs) old +update (Shortcut [] (Right _)) [] new = + return $ Shortcut [] (Right new) +update (Shortcut (o:os) to) (p:ps) new | o == p + = update (Shortcut os to) ps new >>= addPrefix [o] + | otherwise = do + oldRef <- case to of + (Left ref) -> getNode ref >>= addPrefix os >>= putNode + (Right val) -> insertRef emptyRef os val + newRef <- insertRef emptyRef ps new + let refs = Seq.update (num p) newRef $ Seq.update (num o) oldRef emptyRefs + return $ Full refs BS.empty +update (Shortcut (o:os) (Left ref)) [] new = do + newRef <- getNode ref >>= addPrefix os >>= putNode + return $ Full (Seq.update (num o) newRef emptyRefs) new +update (Shortcut cut (Left ref)) ps new = do + newRef <- insertRef ref ps new + return $ Shortcut cut (Left newRef) delete :: Node -> Path -> NodeDB Node delete Empty _ = return Empty @@ -155,17 +167,22 @@ delete n@(Shortcut [] (Right _)) _ = return n delete (Shortcut [] (Left ref)) p = do node <- getNode ref delete node p delete n@(Shortcut _ _) [] = return n -delete n@(Shortcut (o:os) to) (p:ps) | p == o = delete (Shortcut os to) ps >>= addPrefix [o] - | otherwise = return n -delete (Full refs _) [] | refs == emptyRefs = return Empty - | otherwise = return (Full refs BS.empty) -delete (Full refs val) (p:ps) = do newRef <- insertRef (refs `Seq.index` (num p)) ps BS.empty - let newRefs = Seq.update (num p) newRef refs - nonEmpties = filter (\(_, ref) -> ref /= emptyRef) $ zip [0..15] $ toList newRefs - case (nonEmpties, BS.null val) of - (([]), True) -> return Empty - ((n, ref):[], True) -> getNode ref >>= addPrefix [Nibble n] - _ -> return $ Full newRefs val +delete n@(Shortcut (o:os) to) (p:ps) | p == o + = delete (Shortcut os to) ps >>= addPrefix [o] + | otherwise + = return n +delete (Full refs _) [] | refs == emptyRefs + = return Empty + | otherwise + = return (Full refs BS.empty) +delete (Full refs val) (p:ps) = do + newRef <- insertRef (refs `Seq.index` (num p)) ps BS.empty + let newRefs = Seq.update (num p) newRef refs + nonEmpties = filter (\(_, ref) -> ref /= emptyRef) $ zip [0..15] $ toList newRefs + case (nonEmpties, BS.null val) of + (([]), True) -> return Empty + ((n, ref):[], True) -> getNode ref >>= addPrefix [Nibble n] + _ -> return $ Full newRefs val insert :: Ref -> ByteString -> ByteString -> NodeDB Ref insert ref key val = insertRef ref (unpackNibbles key) val