mirror of https://github.com/voidlizard/hbs2
168 lines
6.4 KiB
Haskell
168 lines
6.4 KiB
Haskell
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||
module HBS2.Refs.Linear where
|
||
|
||
import HBS2.Actors
|
||
import HBS2.Clock
|
||
import HBS2.Data.Types.Refs
|
||
import HBS2.Defaults
|
||
import HBS2.Events
|
||
import HBS2.Hash
|
||
import HBS2.Net.Auth.Credentials
|
||
import HBS2.Net.Messaging
|
||
import HBS2.Net.PeerLocator
|
||
import HBS2.Net.PeerLocator.Static
|
||
import HBS2.Net.Proto
|
||
import HBS2.Net.Proto.Sessions
|
||
import HBS2.OrDie
|
||
import HBS2.Prelude.Plated
|
||
import HBS2.Storage
|
||
|
||
import Codec.Serialise (serialise, deserialiseOrFail)
|
||
import Data.ByteString.Lazy qualified as LBS
|
||
import Data.Maybe
|
||
import Data.Set qualified as Set
|
||
|
||
modifyLinearRef :: forall e st block.
|
||
( Signatures e
|
||
, Serialise (Signature e)
|
||
, Serialise (PubKey 'Sign e)
|
||
, Eq (PubKey 'Sign e)
|
||
, Block block ~ LBS.ByteString
|
||
, Storage (st HbSync) HbSync block IO
|
||
)
|
||
=> st HbSync
|
||
-> PeerCredentials e -- owner keyring
|
||
-> Hash HbSync -- channel id
|
||
-> (Maybe (Hash HbSync) -> IO (Hash HbSync))
|
||
-> IO ()
|
||
modifyLinearRef ss kr chh modIO = do
|
||
g :: RefGenesis e <- (((either (const Nothing) Just . deserialiseOrFail) =<<)
|
||
<$> getBlock ss chh)
|
||
`orDie` "can not read channel ref genesis"
|
||
when (refOwner g /= _peerSignPk kr) do
|
||
(pure Nothing) `orDie` "channel ref owner does not match genesis owner"
|
||
mrefvalraw <- readLinkRaw ss chh
|
||
lmr <- case mrefvalraw of
|
||
Nothing -> do
|
||
val <- modIO Nothing
|
||
pure LinearMutableRef
|
||
{ lrefId = chh
|
||
, lrefHeight = 0
|
||
, lrefVal = val
|
||
}
|
||
Just refvalraw -> do
|
||
LinearMutableRefSigned _ ref :: Signed SignaturePresent (MutableRef e 'LinearRef)
|
||
<- pure ((either (const Nothing) Just . deserialiseOrFail) refvalraw)
|
||
`orDie` "can not parse channel ref"
|
||
-- guard $ lrefId ref == chh
|
||
val <- modIO (Just (lrefVal ref))
|
||
pure LinearMutableRef
|
||
{ lrefId = chh
|
||
, lrefHeight = lrefHeight ref + 1
|
||
, lrefVal = val
|
||
}
|
||
(writeLinkRaw ss chh . serialise)
|
||
(LinearMutableRefSigned @e ((makeSign @e (_peerSignSk kr) . LBS.toStrict . serialise) lmr) lmr)
|
||
`orDie` "can not write link"
|
||
pure ()
|
||
|
||
verifyLinearMutableRefSigned :: forall e. (Signatures e)
|
||
=> PubKey 'Sign e
|
||
-> Signed SignaturePresent (MutableRef e 'LinearRef)
|
||
-> Maybe (Signed SignatureVerified (MutableRef e 'LinearRef))
|
||
verifyLinearMutableRefSigned pk lref = do
|
||
guard $ verifySign @e pk (lmrefSignature lref) dat
|
||
pure (LinearMutableRefSignatureVerified (lmrefSignature lref) (lmrefSignedRef lref) pk)
|
||
where
|
||
dat = (LBS.toStrict . serialise) (lmrefSignedRef lref)
|
||
|
||
tryUpdateLinearRef :: forall e st block.
|
||
( Signatures e
|
||
, Serialise (Signature e)
|
||
, Serialise (PubKey 'Sign e)
|
||
, Eq (PubKey 'Sign e)
|
||
, Block block ~ LBS.ByteString
|
||
, Storage (st HbSync) HbSync block IO
|
||
)
|
||
=> st HbSync
|
||
-> Hash HbSync -- channel id
|
||
-> Signed SignatureVerified (MutableRef e 'LinearRef)
|
||
-> IO Bool
|
||
tryUpdateLinearRef ss chh vlref = do
|
||
g :: RefGenesis e <- (((either (const Nothing) Just . deserialiseOrFail) =<<)
|
||
<$> getBlock ss chh)
|
||
`orDie` "can not read channel ref genesis"
|
||
when (refOwner g /= lmrefVSigner vlref) do
|
||
(pure Nothing) `orDie` "channel ref signer does not match genesis owner"
|
||
-- Достать наше текущее значение ссылки, сравнить счётчик
|
||
mrefvalraw <- readLinkRaw ss chh
|
||
allowUpdate <- case mrefvalraw of
|
||
Nothing -> pure True
|
||
Just refvalraw -> do
|
||
LinearMutableRefSigned _ ref :: Signed SignaturePresent (MutableRef e 'LinearRef)
|
||
<- pure ((either (const Nothing) Just . deserialiseOrFail) refvalraw)
|
||
`orDie` "can not parse channel ref"
|
||
-- Если новое значение больше, обновить его
|
||
pure (lrefHeight ref < lrefHeight (lmrefVSignedRef vlref))
|
||
if allowUpdate
|
||
then do
|
||
(writeLinkRaw ss chh . serialise)
|
||
(LinearMutableRefSigned @e (lmrefVSignature vlref) (lmrefVSignedRef vlref))
|
||
`orDie` "can not write link"
|
||
pure True
|
||
else (pure False)
|
||
|
||
modifyNodeLinearRefList :: forall e st block.
|
||
( Signatures e
|
||
, Serialise (Signature e)
|
||
, Serialise (PubKey 'Sign e)
|
||
, Eq (PubKey 'Sign e)
|
||
, Block block ~ LBS.ByteString
|
||
, Storage (st HbSync) HbSync block IO
|
||
)
|
||
=> st HbSync -> PeerCredentials e -> Hash HbSync -> ([Hash HbSync] -> [Hash HbSync]) -> IO ()
|
||
modifyNodeLinearRefList ss kr chh f =
|
||
modifyLinearRef ss kr chh \mh -> do
|
||
v <- case mh of
|
||
Nothing -> pure mempty
|
||
Just h -> fromMaybe mempty . ((either (const Nothing) Just . deserialiseOrFail) =<<)
|
||
<$> getBlock ss h
|
||
(putBlock ss . serialise) (f v)
|
||
`orDie` "can not put new node channel list block"
|
||
|
||
readNodeLinearRefList :: forall e st block.
|
||
( Signatures e
|
||
, Serialise (Signature e)
|
||
, Serialise (PubKey 'Sign e)
|
||
, Eq (PubKey 'Sign e)
|
||
, Block block ~ LBS.ByteString
|
||
, Storage (st HbSync) HbSync block IO
|
||
)
|
||
=> st HbSync -> PubKey 'Sign e -> IO [Hash HbSync]
|
||
readNodeLinearRefList ss pk = do
|
||
-- полученный хэш будет хэшем ссылки на список референсов ноды
|
||
lrh :: h <- pure $ (hashObject . serialise) (nodeLinearRefsRef @e pk)
|
||
readLinkRaw ss lrh >>= \case
|
||
Nothing -> pure []
|
||
Just refvalraw -> do
|
||
LinearMutableRefSigned _ ref
|
||
<- pure ((either (const Nothing) Just . deserialiseOrFail @(Signed SignaturePresent (MutableRef e 'LinearRef))) refvalraw)
|
||
`orDie` "can not parse channel ref"
|
||
fromMaybe mempty . ((either (const Nothing) Just . deserialiseOrFail) =<<)
|
||
<$> getBlock ss (lrefVal ref)
|
||
|
||
nodeRefListAdd :: forall e st block.
|
||
( Signatures e
|
||
, Serialise (Signature e)
|
||
, Serialise (PubKey 'Sign e)
|
||
, Eq (PubKey 'Sign e)
|
||
, Block block ~ LBS.ByteString
|
||
, Storage (st HbSync) HbSync block IO
|
||
)
|
||
=> st HbSync -> PeerCredentials e -> Hash HbSync -> IO ()
|
||
nodeRefListAdd ss nodeCred chh = do
|
||
-- полученный хэш будет хэшем ссылки на список референсов ноды
|
||
lrh <- (putBlock ss . serialise) (nodeLinearRefsRef @e (_peerSignPk nodeCred))
|
||
`orDie` "can not create node refs genesis"
|
||
modifyNodeLinearRefList ss nodeCred lrh $ Set.toList . Set.insert chh . Set.fromList
|