diff --git a/lib/core/src/Cardano/Pool/Metadata.hs b/lib/core/src/Cardano/Pool/Metadata.hs index 145bfe7380e..d165b7cd6bd 100644 --- a/lib/core/src/Cardano/Pool/Metadata.hs +++ b/lib/core/src/Cardano/Pool/Metadata.hs @@ -15,6 +15,7 @@ module Cardano.Pool.Metadata ( -- * Types StakePoolMetadata (..) + , sameStakePoolMetadata , StakePoolTicker -- * Fetching metadata @@ -119,6 +120,12 @@ data StakePoolMetadata = StakePoolMetadata -- ^ Bech32-encoded address. } deriving (Eq, Show, Generic) +-- | Returns 'True' iff metadata is exactly equal, modulo 'PoolOwner'. +sameStakePoolMetadata :: StakePoolMetadata -> StakePoolMetadata -> Bool +sameStakePoolMetadata a b = a { owner = same } == b { owner = same } + where + same = PoolOwner mempty + -- | Very short name for a stake pool. newtype StakePoolTicker = StakePoolTicker { unStakePoolTicker :: Text } deriving stock (Generic, Show, Eq) diff --git a/lib/core/src/Cardano/Pool/Metrics.hs b/lib/core/src/Cardano/Pool/Metrics.hs index b8b8fa68ecf..e60eea8e856 100644 --- a/lib/core/src/Cardano/Pool/Metrics.hs +++ b/lib/core/src/Cardano/Pool/Metrics.hs @@ -34,6 +34,9 @@ module Cardano.Pool.Metrics , combineMetrics , calculatePerformance + -- * Associating metadata + , associateMetadata + -- * Logging , StakePoolLayerMsg (..) ) @@ -54,6 +57,7 @@ import Cardano.Pool.Metadata , StakePoolMetadata (..) , getRegistryZipUrl , getStakePoolMetadata + , sameStakePoolMetadata ) import Cardano.Wallet.Logging ( logTrace ) @@ -285,7 +289,7 @@ newStakePoolLayer db@DBLayer{..} nl tr = StakePoolLayer (Map.fromList $ zip poolIds owners) (zip owners' metas) mapM_ (logTrace tr . fst) res - pure (map snd res) + pure $ map snd res (block0, bp) = staticBlockchainParameters nl epochLength = bp ^. #getEpochLength @@ -548,7 +552,7 @@ associateMetadata poolOwners ownerMeta = [] -> (MsgMetadataMissing pid, Nothing) metas' -> (MsgMetadataMultiple pid metas', Nothing) - sameMeta (_, a) (_, b) = a == b + sameMeta (_, a) (_, b) = sameStakePoolMetadata a b {------------------------------------------------------------------------------- Logging diff --git a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs index 297360bf4cc..291db5d1ac2 100644 --- a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs +++ b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs @@ -10,8 +10,15 @@ module Cardano.Pool.MetricsSpec (spec) where import Prelude +import Cardano.Pool.Metadata + ( StakePoolMetadata (..), sameStakePoolMetadata ) import Cardano.Pool.Metrics - ( Block (..), calculatePerformance, combineMetrics ) + ( Block (..) + , StakePoolLayerMsg (..) + , associateMetadata + , calculatePerformance + , combineMetrics + ) import Cardano.Wallet.Primitive.Types ( BlockHeader (..) , Coin (..) @@ -24,8 +31,12 @@ import Cardano.Wallet.Primitive.Types , flatSlot , fromFlatSlot ) +import Cardano.Wallet.Unsafe + ( unsafeFromText ) import Data.Function ( (&) ) +import Data.List + ( sort ) import Data.Map.Strict ( Map ) import Data.Quantity @@ -33,7 +44,7 @@ import Data.Quantity import Data.Word ( Word32, Word64 ) import Test.Hspec - ( Spec, describe, it, shouldBe ) + ( Spec, describe, it, shouldBe, shouldContain, shouldSatisfy ) import Test.QuickCheck ( Arbitrary (..) , NonNegative (..) @@ -54,6 +65,7 @@ import Test.QuickCheck.Arbitrary.Generic import qualified Data.ByteString.Char8 as B8 import qualified Data.Map.Strict as Map +import qualified Data.Text.Encoding as T spec :: Spec spec = do @@ -72,6 +84,8 @@ spec = do describe "golden test cases" $ do performanceGoldens + associateMetadataSpec + {------------------------------------------------------------------------------- Properties -------------------------------------------------------------------------------} @@ -227,3 +241,69 @@ instance Arbitrary PoolRegistrationCertificate where arbitrary = PoolRegistrationCertificate <$> arbitrary <*> arbitrary shrink (PoolRegistrationCertificate p o) = uncurry PoolRegistrationCertificate <$> shrink (p, o) + +{------------------------------------------------------------------------------- + Unit tests +-------------------------------------------------------------------------------} + +associateMetadataSpec :: Spec +associateMetadataSpec = describe "associateMetadata" $ do + let mkMetadata owner@(PoolOwner bs) tckr = StakePoolMetadata + { owner = owner + , ticker = unsafeFromText tckr + , name = tckr + , description = Just tckr + , homepage = tckr + , pledgeAddress = tckr + } + + it "works in sunny day case" $ do + let owner = PoolOwner "a" + let md = mkMetadata owner "AAAA" + let pid = PoolId "1" + + let res = associateMetadata + (Map.fromList [(pid, [owner])]) + [(owner, Just md)] + + res `shouldBe` [(MsgMetadataUsing pid owner md, Just md)] + + it "missing metadata" $ do + let res = associateMetadata + (Map.fromList [(PoolId "1", [PoolOwner "a"])]) + [(PoolOwner "a", Nothing)] + + res `shouldBe` [(MsgMetadataMissing (PoolId "1"), Nothing)] + + it "duplicate metadata" $ do + let mda = mkMetadata (PoolOwner "a") "AAAA" + let mdb = mkMetadata (PoolOwner "b") "AAAA" + let [(msg, res)] = associateMetadata + (Map.fromList [(PoolId "1", [PoolOwner "a", PoolOwner "b"])]) + [ (PoolOwner "a", Just mda) + , (PoolOwner "b", Just mdb) + ] + + case msg of + MsgMetadataUsing pid owner md -> do + pid `shouldBe` PoolId "1" + [PoolOwner "a", PoolOwner "b"] `shouldContain` [owner] + md `shouldSatisfy` sameStakePoolMetadata mda + md `shouldSatisfy` sameStakePoolMetadata mdb + _ -> fail $ "wrong log message " ++ show msg + + fmap (sameStakePoolMetadata mda) res `shouldBe` Just True + + it "inconsistent metadata" $ do + let mda = mkMetadata (PoolOwner "a") "AAAA" + let mdb = mkMetadata (PoolOwner "b") "BBBB" + + let res = associateMetadata + (Map.fromList [(PoolId "1", [PoolOwner "a", PoolOwner "b"])]) + [ (PoolOwner "a", Just mda) + , (PoolOwner "b", Just mdb) + ] + + res `shouldBe` + [( MsgMetadataMultiple (PoolId "1") + [(PoolOwner "a", mda), (PoolOwner "b", mdb)], Nothing)]