Skip to content
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

ADP-478: Garbage collect delisted stake pools from SMASH #2249

Merged
merged 29 commits into from
Nov 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c6e9260
Add `delistPools` to Pool DBLayer
Oct 15, 2020
45e1a88
Add delisted to swagger.yaml
Oct 16, 2020
903440d
Add internal_state table
Oct 16, 2020
1896b34
Add GC worker thread for delisting Pools
Oct 16, 2020
fbbf8c0
Return GC sync time as well from ListStakePools
Oct 17, 2020
88c6cff
Add stake pool maintenance endpoint
Oct 17, 2020
04f3415
Change DB representation of POSIXTime
Oct 17, 2020
7ed274a
Add DB test for last GC time
Oct 17, 2020
3192c4e
Add property test for `delistPools`
Oct 26, 2020
fbb57d0
Redo how we report GC status of metadata
Oct 27, 2020
456ee2d
Add /stake-pools/metadata-gc-status endpoint
Oct 27, 2020
7b65f3d
Add prop_delistPoolsPersists, which fails right now
Oct 27, 2020
55ddb80
Fix putPoolRegisration to consider the delisted flag
Oct 27, 2020
173f9ed
Add 'ApiT PoolMetadataGCStatus' to json roundtrip explicitly
Oct 27, 2020
de490f5
Fix 'Arbitrary (ApiListStakePools ApiStakePool)'
Oct 27, 2020
7f17cb5
Add missing golden files
Oct 27, 2020
abf915e
Update lib/shelley/src/Cardano/Wallet/Shelley/Pools.hs
Oct 28, 2020
71b0d6b
Update lib/core/src/Cardano/Wallet/Api/Types.hs
Oct 28, 2020
204e685
Record delisted pools in a dedicated table.
jonathanknowles Oct 28, 2020
cf7a5ad
Rename `delisted_pools` table to `pool_delistment`.
jonathanknowles Oct 28, 2020
4b3c36b
Make `delistPools` replace the set of delisted pools.
jonathanknowles Oct 28, 2020
90873a8
Rename `delistPools` to `putDelistedPools`.
jonathanknowles Oct 28, 2020
08df4e1
Update `prop_putDelistedPools` to check for overwriting.
jonathanknowles Oct 28, 2020
2995450
Remove `prop_putDelistedPoolsPersists`.
jonathanknowles Oct 28, 2020
b564500
Adjust `removePools` to not remove pools from the delisted set.
jonathanknowles Oct 28, 2020
0b8df37
Move maintenance-actions to its own endpoint
Nov 9, 2020
4a70362
Fix swagger definition
Nov 9, 2020
105ec6a
Regenerate nix
Nov 6, 2020
6489807
unify gcPoolStatus and maintenance action for a cleaner API
KtorZ Nov 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ spec :: forall n t.
) => SpecWith (Context t)
spec = describe "SHELLEY_STAKE_POOLS" $ do
let listPools ctx stake = request @[ApiStakePool] ctx
(Link.listStakePools stake) Default Empty
(Link.listStakePools stake) Default Empty

it "STAKE_POOLS_JOIN_01 - Cannot join non-existent wallet" $ \ctx -> runResourceT $ do
w <- emptyWallet ctx
Expand All @@ -165,7 +165,8 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
\Cannot join existent stakepool with wrong password" $ \ctx -> runResourceT $ do
w <- fixtureWallet ctx
pool:_ <- map (view #id) . snd <$> unsafeRequest
@[ApiStakePool] ctx (Link.listStakePools arbitraryStake) Empty
@[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
joinStakePool @n ctx pool (w, "Wrong Passphrase") >>= flip verify
[ expectResponseCode HTTP.status403
, expectErrorMessage errMsg403WrongPass
Expand All @@ -178,7 +179,8 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
dest <- emptyWallet ctx

-- Join Pool
pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool] ctx
pool:_ <- map (view #id) . snd <$>
unsafeRequest @[ApiStakePool] ctx
(Link.listStakePools arbitraryStake) Empty
joinStakePool @n ctx pool (src, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status202
Expand Down Expand Up @@ -355,8 +357,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
it "STAKE_POOLS_JOIN_02 - \
\Cannot join already joined stake pool" $ \ctx -> runResourceT $ do
w <- fixtureWallet ctx
pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd
<$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
joinStakePool @n ctx pool (w, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status202
, expectField (#status . #getApiT) (`shouldBe` Pending)
Expand Down Expand Up @@ -404,8 +407,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do

it "STAKE_POOLS_QUIT_02 - Passphrase must be correct to quit" $ \ctx -> runResourceT $ do
w <- fixtureWallet ctx
pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd
<$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
joinStakePool @n ctx pool (w, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status202
, expectField (#status . #getApiT) (`shouldBe` Pending)
Expand Down Expand Up @@ -444,8 +448,8 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
waitForNextEpoch ctx

pool1:pool2:_ <- map (view #id) . snd
<$> unsafeRequest @[ApiStakePool] ctx
(Link.listStakePools arbitraryStake) Empty
<$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty

joinStakePool @n ctx pool1 (w, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status202
Expand Down Expand Up @@ -509,8 +513,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do

it "STAKE_POOLS_JOIN_04 - Rewards accumulate" $ \ctx -> runResourceT $ do
w <- fixtureWallet ctx
pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd
<$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
-- Join a pool
joinStakePool @n ctx pool (w, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status202
Expand Down Expand Up @@ -557,8 +562,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
} |]

w <- unsafeResponse <$> postWallet ctx payload
pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd <$>
unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty

eventually "wallet join a pool" $ do
joinStakePool @n ctx pool (w, fixturePassphrase) >>= flip verify
Expand Down Expand Up @@ -685,8 +691,8 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
$ it "Join/quit when already joined a pool" $ \ctx -> runResourceT $ do
w <- fixtureWallet ctx

pool1:pool2:_ <-
map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
pool1:pool2:_ <- map (view #id) . snd <$>
unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty

liftIO $ joinStakePool @n ctx pool1 (w, fixturePassphrase) >>= flip verify
Expand Down Expand Up @@ -755,8 +761,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
it "STAKE_POOLS_JOIN_01x - \
\I can join if I have just the right amount" $ \ctx -> runResourceT $ do
w <- fixtureWalletWith @n ctx [costOfJoining ctx + depositAmt ctx]
pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd <$>
unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
joinStakePool @n ctx pool (w, fixturePassphrase)>>= flip verify
[ expectResponseCode HTTP.status202
, expectField (#status . #getApiT) (`shouldBe` Pending)
Expand All @@ -766,8 +773,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
it "STAKE_POOLS_JOIN_01x - \
\I cannot join if I have not enough fee to cover" $ \ctx -> runResourceT $ do
w <- fixtureWalletWith @n ctx [costOfJoining ctx + depositAmt ctx - 1]
pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd <$>
unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
joinStakePool @n ctx pool (w, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status403
, expectErrorMessage (errMsg403DelegationFee 1)
Expand All @@ -788,8 +796,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
]
w <- fixtureWalletWith @n ctx initBalance

pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd
<$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty

joinStakePool @n ctx pool (w, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status202
Expand Down Expand Up @@ -824,8 +833,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
let initBalance = [ costOfJoining ctx + depositAmt ctx ]
w <- fixtureWalletWith @n ctx initBalance

pool:_ <- map (view #id) . snd <$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty
pool:_ <- map (view #id) . snd
<$> unsafeRequest @[ApiStakePool]
ctx (Link.listStakePools arbitraryStake) Empty

joinStakePool @n ctx pool (w, fixturePassphrase) >>= flip verify
[ expectResponseCode HTTP.status202
Expand Down Expand Up @@ -898,18 +908,18 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
r <- listPools ctx arbitraryStake
expectResponseCode HTTP.status200 r
let oneMillionAda = 1_000_000_000_000
let pools = either (error . show) Prelude.id $ snd r
let pools' = either (error . show) Prelude.id $ snd r

-- To ignore the ordering of the pools, we use Set.
setOf pools (view #cost)
setOf pools' (view #cost)
`shouldBe` Set.singleton (Quantity 0)

setOf pools (view #margin)
setOf pools' (view #margin)
`shouldBe`
Set.singleton
(Quantity $ unsafeMkPercentage 0.1)

setOf pools (view #pledge)
setOf pools' (view #pledge)
`shouldBe`
Set.fromList
[ Quantity oneMillionAda
Expand Down Expand Up @@ -960,9 +970,9 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do

verify r
[ expectListSize 3
, expectField Prelude.id $ \pools -> do
, expectField Prelude.id $ \pools' -> do
let metadataActual = Set.fromList $
mapMaybe (fmap getApiT . view #metadata) pools
mapMaybe (fmap getApiT . view #metadata) pools'
metadataActual
`shouldSatisfy` (`Set.isSubsetOf` metadataPossible)
metadataActual
Expand All @@ -971,11 +981,12 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do

it "contains and is sorted by non-myopic-rewards" $ \ctx -> runResourceT $ do
eventually "eventually shows non-zero rewards" $ do
Right pools@[pool1,_pool2,pool3] <-
Right pools'@[pool1,_pool2,pool3] <-
snd <$> listPools ctx arbitraryStake
let rewards = view (#metrics . #nonMyopicMemberRewards)
(rewards <$> pools) `shouldBe`
(rewards <$> sortOn (Down . rewards) pools)

(rewards <$> pools') `shouldBe`
(rewards <$> sortOn (Down . rewards) pools')
-- Make sure the rewards are not all equal:
rewards pool1 .> rewards pool3

Expand All @@ -1001,7 +1012,8 @@ spec = describe "SHELLEY_STAKE_POOLS" $ do
\NonMyopicMemberRewards are 0 when stake is 0" $ \ctx -> runResourceT $ do
liftIO $ pendingWith "This assumption seems false, for some reasons..."
let stake = Just $ Coin 0
r <- request @[ApiStakePool] ctx (Link.listStakePools stake)
r <- request @[ApiStakePool]
ctx (Link.listStakePools stake)
Default Empty
expectResponseCode HTTP.status200 r
verify r
Expand Down
2 changes: 1 addition & 1 deletion lib/core/cardano-wallet-core.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ library
, statistics
, stm
, streaming-commons
, string-qq
, string-interpolate
, template-haskell
, text
, text-class
Expand Down
21 changes: 21 additions & 0 deletions lib/core/src/Cardano/Pool/DB.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ import Data.Map.Strict
( Map )
import Data.Quantity
( Quantity (..) )
import Data.Time.Clock.POSIX
( POSIXTime )
import Data.Word
( Word64 )
import System.Random
Expand Down Expand Up @@ -211,6 +213,16 @@ data DBLayer m = forall stm. (MonadFail stm, MonadIO stm) => DBLayer
-> stm ()
-- ^ Remove all entries of slot ids newer than the argument

, putDelistedPools
:: [PoolId]
-> stm ()
-- ^ Overwrite the set of delisted pools with a completely new set.
-- Pools may be delisted for reasons such as non-compliance.

, readDelistedPools
:: stm [PoolId]
-- ^ Fetch the set of delisted pools.

, removePools
:: [PoolId]
-> stm ()
Expand Down Expand Up @@ -249,6 +261,15 @@ data DBLayer m = forall stm. (MonadFail stm, MonadIO stm) => DBLayer
-> stm ()
-- ^ Modify the settings.

, readLastMetadataGC
:: stm (Maybe POSIXTime)
-- ^ Get the last metadata GC time.

, putLastMetadataGC
:: POSIXTime
-> stm ()
-- ^ Set the last metadata GC time.
--
, cleanDB
:: stm ()
-- ^ Clean a database
Expand Down
15 changes: 15 additions & 0 deletions lib/core/src/Cardano/Pool/DB/MVar.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,19 @@ import Cardano.Pool.DB.Model
, mListPoolLifeCycleData
, mListRegisteredPools
, mListRetiredPools
, mPutDelistedPools
, mPutFetchAttempt
, mPutHeader
, mPutLastMetadataGC
, mPutPoolMetadata
, mPutPoolProduction
, mPutPoolRegistration
, mPutPoolRetirement
, mPutSettings
, mPutStakeDistribution
, mReadCursor
, mReadDelistedPools
, mReadLastMetadataGC
, mReadPoolLifeCycleStatus
, mReadPoolMetadata
, mReadPoolProduction
Expand Down Expand Up @@ -146,6 +150,12 @@ newDBLayer timeInterpreter = do
rollbackTo =
void . alterPoolDB (const Nothing) db . mRollbackTo timeInterpreter

putDelistedPools =
void . alterPoolDB (const Nothing) db . mPutDelistedPools

readDelistedPools =
readPoolDB db mReadDelistedPools

removePools =
void . alterPoolDB (const Nothing) db . mRemovePools

Expand All @@ -165,6 +175,11 @@ newDBLayer timeInterpreter = do
putSettings =
void . alterPoolDB (const Nothing) db . mPutSettings

readLastMetadataGC = readPoolDB db mReadLastMetadataGC

putLastMetadataGC =
void . alterPoolDB (const Nothing) db . mPutLastMetadataGC

cleanDB =
void $ alterPoolDB (const Nothing) db mCleanDatabase

Expand Down
Loading