-
Notifications
You must be signed in to change notification settings - Fork 217
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
Adding ticking functionality for block polling #35
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you were a bit off track here and went for more than what was needed. It's important to separate concerns in your implementation and make sure that code isn't needlessly coupled to some other code.
It would have been nice to get a PR much sooner actually to prevent this; as per our new development process, we want to keep on at least one PR a day so make sure to break a task down to iterations that are achievable within a day. Mocking isn't usually a good idea, but inversion of control may help a lot.
Also, make sure to go through and acknowledge the coding standards once again. It's important for us all to be consistent on the practices.
src/Cardano/Wallet/BlockSyncer.hs
Outdated
getBlock :: (Hash "BlockHeader") -> IO Block | ||
, getEpoch :: Word64 -> IO [Block] | ||
, getNetworkTip :: IO ((Hash "BlockHeader"),BlockHeader) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This, and the implementation below of the mockup are only for testing I presume 🤔 ? I wouldn't expect this to be needed for writing and testing the ticking function. Cf next comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was supposed to act like that. in the light of the refactoring it is not used anymore
src/Cardano/Wallet/BlockSyncer.hs
Outdated
:: Int | ||
-> [((Hash "BlockHeader"),Block)] | ||
-> Int | ||
-> IO BlockLayerMockup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General remark about function API, but primitive types like Int
or String
communicate badly about their usage. It's always a good idea to add a comment explaining what the parameter is for. It's usually an even better idea to create a proper type to encapsulate that semantic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
src/Cardano/Wallet/BlockSyncer.hs
Outdated
blockSyncerBracket blocksPersisted blockLayer period = | ||
bracket | ||
(return ()) --(putStrLn "setting up for ticking function") | ||
(\_->return ()) --(\_ -> putStrLn "cleaning for ticking function") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code shouldn't be pushed / committed (unless it serves as an example for documentation), which isn't the case here 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put it like that for the sake of future logging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't :)
If it's not needed, don't do it. We favor simple code and refactor when we need to add functionalities 👍
src/Cardano/Wallet/BlockSyncer.hs
Outdated
missingHashes <- retrieveMissingBlocks [previousHeaderHash] | ||
headerHashesConsumed | ||
blockLayer | ||
pure $ currentHeaderHash : (missingHashes ++ headerHashesConsumed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to follow the coding standards on variable-length indentation 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
src/Cardano/Wallet/BlockSyncer.hs
Outdated
:: IORef BlocksConsumed | ||
-> BlockLayerMockup | ||
-> Int | ||
-> () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very dubious 😶
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still wonder why have this unit argument here?
src/Cardano/Wallet/BlockSyncer.hs
Outdated
pure $ currentHeaderHash : (missingHashes ++ headerHashesConsumed) | ||
writeIORef initialState $ BlocksConsumed updatedHeaderHashes | ||
threadDelay (delayPeriod*1000*1000) | ||
go previousState |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so here's the thing. This function seems a bit too explicit and conflates several responsabilities into one. As a rule of thumb, function should do one and one thing, and try not to work at different abstraction level. If we step back a little and re-think a bit the requirements / design of such function.
- It's about ticking / polling a source of blocks and, proceed with some action when a new block is identified.
This means that we need:
- A way to poll a source and get the latest block from a source
- An action to execute when a new block is received
We want to leave it to the caller to define such behavior, and the ticking function should just bother
about keeping track of that latest block and calling an action when a new one is discovered.
How blocks are fetched and what action is executed matters not; So we can inject the corresponding
behaviors from the arguments:
tickingFunction
:: IO Block
-> (Block -> IO ())
-> IO ()
tickingFunction getNextBlock action = do
-- ...
Then, the implementation shouldn't do much more than keeping track of the
previous block fetched, and regularly polling the chain to fetch the one,
calling the action whenever the block fetched is different from the latest
block fetched.
There's no particular need for mocking here, because the behavior of how you get blocks doesn't matter
for the ticking function; this incidentally makes testing way easier because you get to choose that
behavior in your testing code!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
complied. Thanks for detailed directions
src/Cardano/Wallet/BlockSyncer.hs
Outdated
-> [(Hash "BlockHeader")] | ||
-> BlockLayerMockup | ||
-> IO [(Hash "BlockHeader")] | ||
retrieveMissingBlocks missing headerHashesConsumed layer = do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is out of scope for this task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I removed that
import Cardano.Wallet.BlockSyncer | ||
( BlocksConsumed (..), blockSyncerBracket, runBlockLayerMockup ) | ||
import Cardano.Wallet.Primitive | ||
( Block (..), BlockHeader (..), Hash (..) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to follow the coding standards for imports 🙏 (two groups, qualified vs explicit imports. We do not make any more groups based on whether the code comes from our code base or not).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
testBlocksPolling | ||
:: Int | ||
-> Int | ||
-> Int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In such case, think about using a record type to make the intent clear about what the parameters are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:-)
threadDelay (testTimeEvalInSec*1000*1000) | ||
killThread threadID | ||
(BlocksConsumed finalHeaderHashes) <- readIORef initialHeaderData | ||
finalHeaderHashes `shouldBe` (map fst consecutiveBlocks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this function would deserve to be split in multiple ones that each encapsulate a particular responsibility. It would make the organization of the code a bit clearer between how the test is being set up, what the test action is and what are the expectations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do it in the final commit
2bc23be
to
84ad4f5
Compare
(BlocksConsumed consumedData) <- readIORef consumerData | ||
|
||
consumedData `shouldBe` ((map fst . reverse) consecutiveBlocks) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is further refactoring under way
src/Cardano/Wallet/BlockSyncer.hs
Outdated
bracket | ||
(return ()) | ||
(\_->return ()) | ||
(tickingFunction getNextBlocks action tickTime) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is the kind of "not needed yet abstractions" I am often referring too. The bracket doesn't buy us anything here, and there's no particular need to have such bracket. Maybe later we'll have to get some resources before calling the ticking function, but that's later. As for now, we just want to have a ticking function and test it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed bracket as requested
src/Cardano/Wallet/BlockSyncer.hs
Outdated
tickingFunction | ||
:: IO [Block] | ||
-> (Block -> IO ()) | ||
-> Int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be better to get a better type here which convey a clear meaning -- or... not having any at all. The time can just be a hard-coded constant on top of the module, if we ever need to change that, we'll make it a parameter. But again, for now, this parameter isn't needed or required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
went with Second from time-units
src/Cardano/Wallet/BlockSyncer.hs
Outdated
:: IORef BlocksConsumed | ||
-> BlockLayerMockup | ||
-> Int | ||
-> () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still wonder why have this unit argument here?
src/Cardano/Wallet/BlockSyncer.hs
Outdated
(\(e :: SomeException) -> | ||
let msg = "Terminating tickingFunction of BlockSyncer due to " % F.shown | ||
in (putStrLn . showText) $ sformat msg e | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is rather problematic to handle the error here in such way.. If the ticking function dies... as for now, we probably wants the wallet to die too. That's a fatal error and here, we'll just be showing a message in the console and silently fade away. The wallet server will keep running and... nothing will happen until we eventually notice that there's no block getting fetched anymore.
So, until further needs, let just do nothing and let the exception bubbles to the caller.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed and also formatting dependency
|
||
(BlocksConsumed consumedData) <- readIORef consumerData | ||
|
||
consumedData `shouldBe` ((map fst . reverse) consecutiveBlocks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is rather unclear to me what the tests are testing here 🤔 ? A comment or a longer scenario would definitely helps. ASCII diagrams are also very welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to check first ExactlyOnce delivery. When the ticking function gained not-consuming-the-same-block-guarrantee I added also AtLeastOnce delivery test
84ad4f5
to
26ba984
Compare
src/Cardano/Wallet/BlockSyncer.hs
Outdated
newtype BlockHeadersConsumed = BlockHeadersConsumed [BlockHeader] deriving (Show, Eq) | ||
|
||
storingLimit :: Int | ||
storingLimit = 2140 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean 2160
🤔 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, when we later tackle rollback security parameter comes here (I thought about it but made blunder here putting 2140 instead of 2160). For the time being I wanted to just add some upper bound just in order to not surpass memory limit.
@@ -37,13 +37,16 @@ library | |||
, cborg | |||
, containers | |||
, deepseq | |||
, text |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed - will remove in the final commit
26ba984
to
c065308
Compare
problems with tests are because of IORef use. I will refactor the code with MVar |
c065308
to
bc9da3b
Compare
-> Block | ||
-> Bool | ||
checkIfAlreadyConsumed consumedHeaders (Block theHeader _) = | ||
theHeader `L.notElem` consumedHeaders |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, this looks good now. If I may throw a naming suggestion:
-
BlockHeaderConsumed--->Known
with a type parameter, BlockHeader is rather unnecessary here, it's already in the type:Known [BlockHeader]
-
checkIfAlreadyConsumed--->isKnown
, less prose is good :) -
tickTime-->delay
, well, that's what it is in the end. -
blocksDownloaded-->blocks
, again, no need to be extra verbose about this. By keeping your function small, the context is enough to understand this. And, in the end, it doesn't really matter if blocks have been downloaded, or fetched or unserialized .. Unless it helps disambiguate things, go for a short name. -
-->blocksToProcess
block'
orunknownBlock
, just to be aligned with the above suggestions -
-->consumedHeaders
knownHeaders
, also, to be aligned -
-->theHeader
h
is probably enough because the function is really short, or, do not pattern match and go forheader block
orheader b
Short names are usually good. Too short is sometimes not very helpful, though it make sense when working on abstractions (like in filter :: (a -> Bool) -> [a] -> [a]
, one wouldn't write filter :: (theElement -> Bool) -> theList -> theList
).
-> Gen [Int] | ||
generateBlockChunks numberOfTicks = do | ||
let chunkSizeGen = choose (0,15) | ||
vectorOf numberOfTicks chunkSizeGen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would have been nice to have a chat about the approach on testing for this. I think you've got the idea, but the implementation of the tests has gone slightly too complex IMO. I'll make a suggestion a bit later but it would be nice to go through this together.
src/Cardano/Wallet/BlockSyncer.hs
Outdated
-- | ||
-- This module contains the ticking function that is responsible for invoking block acquisition functionality and executing it in periodic fashion. | ||
-- | ||
-- Known limitations: ticking function makes sure action is not executed on already consumed block, but does not check and handle block gaps (aka catching up) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there! We'd need to wrap this to bring the above comment in line with https://github.com/input-output-hk/cardano-wallet/wiki/Coding-Standards#limit-line-length-to-80-characters
Perhaps like this:
-- This module contains the ticking function that is responsible for invoking
-- block acquisition functionality and executing it in periodic fashion.
--
-- Known limitations: the ticking function makes sure action is not executed on
-- already consumed block, but does not check and handle block gaps (aka
-- catching up).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
src/Cardano/Wallet/BlockSyncer.hs
Outdated
import qualified Data.List as L | ||
|
||
|
||
newtype BlockHeadersConsumed = BlockHeadersConsumed [BlockHeader] deriving (Show, Eq) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Propose:
newtype BlockHeadersConsumed =
BlockHeadersConsumed [BlockHeader]
deriving (Show, Eq)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
600f3cf
to
69e2083
Compare
[3] Adding ticking function test and downloading block logic [3] Block syncer working ok plus additional tests [3] Cleaning the code [3] cabal fix [3] Complete refactoring to the review [3] Final refactoring [3] cabal fix [3] hlint and weeding [3] add killing thread at the end of test [3] Replace IORef with MVar refactoring #1 | inline intermediate functions to see more clearly + remove debug console prints refactoring #2 | review indentation of 'where' clause refactoring #3 | inline loop and remove test intrumentation from test logic refactoring #4 | define generator for ticking args in a declarative manner refactoring #5 | purify tickingFunctionTest and make it a monadic property refactoring #6 | review naming in Arbitrary TickingArgs refactoring #7 | use guards in mkConsecutiveTestBlocks refactoring #8 | define single block generator from previous block refactoring #9 | use 'fromPreviousBlock' and start loop with an already initialize list refactoring #10 | purify mkConsecutiveTestBlocks by defining a test hash function refactoring #11 | switch argument positions in mkConsecutiveTestBlocks refactoring #12 | replace loop with built-in list 'iterate' refactoring #13 | define Arbitrary instance for creating consecutive blocks refactoring #14 | replace mkConsecutiveBlocks with a property parameter refactoring #15 | use 'newMVar' instead or 'newEmptyMVar' + 'putMVar' refactoring #16 | remove unecessary IO in 'writeToIORefAction' refactoring #17 | replace takeMVar + putMVar with modifyMVar refactoring #18 | review naming for 'writeToIORefAction' --> 'reader' refactoring #19 | use a 'Map.lookup' instead of 'List.filter' + pattern-match refactoring #20 | remove 'BlocksConsumed' wrapper refactoring #21 | generalize reader with polymorphic parametrism refactoring #22 | review pushNextBlocks indentation refactoring #23 | group case pattern matches using tuple refactoring #24 | remove 'Hash BlockHeader' from the block to inject refactoring #25 | use synchronization lock instead of computed times refactoring #26 | Move generation of duplicated blocks onto 'Arbitrary Blocks' refactoring #27 | remove 'chunkSizes' in a favor of inline random selection refactoring #28 | remove 'DeliveryMode' in favor of the most general case refactoring #29 | cleanup wrapper types refactoring #30 | generalize pushNextBlocks with parametric polymorphism refactoring #31 | rename pushNextBlocks to 'writer' refactoring #32 | define reader on Block instead of BlockHeaderHash refactoring #33 | replace old reader with reader' refactoring #34 | move creation of writer MVar inside writer action refactoring #35 | remove header hash from 'Blocks' refactoring #36 | rename 'consecutiveBlocks' into 'blocks' refactoring #37 | re-organize module to separate effectful logic from declarations refactoring #38 | move waiting logic into dedicated function refactoring #39 | move 'done' and 'readerChan' initialization into reader and writer refactoring #40 | use Millisecond instead of Second for shorter tests refactoring #41 | Move creation of blocks from writer to 'Arbitrary Blocks' [3] fix line width [3] aligning the code with other code changes
rebased and squashed |
it seems we have :
and weeder still keeps complaining about groups and duplicateMaybe not used outside module |
69e2083
to
a423b02
Compare
[3] Adding ticking function test and downloading block logic [3] Block syncer working ok plus additional tests [3] Cleaning the code [3] cabal fix [3] Complete refactoring to the review [3] Final refactoring [3] cabal fix [3] hlint and weeding [3] add killing thread at the end of test [3] Replace IORef with MVar refactoring #1 | inline intermediate functions to see more clearly + remove debug console prints refactoring #2 | review indentation of 'where' clause refactoring #3 | inline loop and remove test intrumentation from test logic refactoring #4 | define generator for ticking args in a declarative manner refactoring #5 | purify tickingFunctionTest and make it a monadic property refactoring #6 | review naming in Arbitrary TickingArgs refactoring #7 | use guards in mkConsecutiveTestBlocks refactoring #8 | define single block generator from previous block refactoring #9 | use 'fromPreviousBlock' and start loop with an already initialize list refactoring #10 | purify mkConsecutiveTestBlocks by defining a test hash function refactoring #11 | switch argument positions in mkConsecutiveTestBlocks refactoring #12 | replace loop with built-in list 'iterate' refactoring #13 | define Arbitrary instance for creating consecutive blocks refactoring #14 | replace mkConsecutiveBlocks with a property parameter refactoring #15 | use 'newMVar' instead or 'newEmptyMVar' + 'putMVar' refactoring #16 | remove unecessary IO in 'writeToIORefAction' refactoring #17 | replace takeMVar + putMVar with modifyMVar refactoring #18 | review naming for 'writeToIORefAction' --> 'reader' refactoring #19 | use a 'Map.lookup' instead of 'List.filter' + pattern-match refactoring #20 | remove 'BlocksConsumed' wrapper refactoring #21 | generalize reader with polymorphic parametrism refactoring #22 | review pushNextBlocks indentation refactoring #23 | group case pattern matches using tuple refactoring #24 | remove 'Hash BlockHeader' from the block to inject refactoring #25 | use synchronization lock instead of computed times refactoring #26 | Move generation of duplicated blocks onto 'Arbitrary Blocks' refactoring #27 | remove 'chunkSizes' in a favor of inline random selection refactoring #28 | remove 'DeliveryMode' in favor of the most general case refactoring #29 | cleanup wrapper types refactoring #30 | generalize pushNextBlocks with parametric polymorphism refactoring #31 | rename pushNextBlocks to 'writer' refactoring #32 | define reader on Block instead of BlockHeaderHash refactoring #33 | replace old reader with reader' refactoring #34 | move creation of writer MVar inside writer action refactoring #35 | remove header hash from 'Blocks' refactoring #36 | rename 'consecutiveBlocks' into 'blocks' refactoring #37 | re-organize module to separate effectful logic from declarations refactoring #38 | move waiting logic into dedicated function refactoring #39 | move 'done' and 'readerChan' initialization into reader and writer refactoring #40 | use Millisecond instead of Second for shorter tests refactoring #41 | Move creation of blocks from writer to 'Arbitrary Blocks' [3] fix line width [3] aligning the code with other code changes [3] hlint suggestion
@paweljakubas Whoops. Sorry about the pragma, I typically do that when developing to iterate quickly and I clean up the imports before making a PR. This should be removed, and imports cleaned up as well 👍 |
ahh, I have already added proper .weeder.yaml being the product of:
We do not want it, right? Just remove pragma and superfluous exports? |
60b16ce
to
33cd68f
Compare
[3] Adding ticking function test and downloading block logic [3] Block syncer working ok plus additional tests [3] Cleaning the code [3] cabal fix [3] Complete refactoring to the review [3] Final refactoring [3] cabal fix [3] hlint and weeding [3] add killing thread at the end of test [3] Replace IORef with MVar refactoring #1 | inline intermediate functions to see more clearly + remove debug console prints refactoring #2 | review indentation of 'where' clause refactoring #3 | inline loop and remove test intrumentation from test logic refactoring #4 | define generator for ticking args in a declarative manner refactoring #5 | purify tickingFunctionTest and make it a monadic property refactoring #6 | review naming in Arbitrary TickingArgs refactoring #7 | use guards in mkConsecutiveTestBlocks refactoring #8 | define single block generator from previous block refactoring #9 | use 'fromPreviousBlock' and start loop with an already initialize list refactoring #10 | purify mkConsecutiveTestBlocks by defining a test hash function refactoring #11 | switch argument positions in mkConsecutiveTestBlocks refactoring #12 | replace loop with built-in list 'iterate' refactoring #13 | define Arbitrary instance for creating consecutive blocks refactoring #14 | replace mkConsecutiveBlocks with a property parameter refactoring #15 | use 'newMVar' instead or 'newEmptyMVar' + 'putMVar' refactoring #16 | remove unecessary IO in 'writeToIORefAction' refactoring #17 | replace takeMVar + putMVar with modifyMVar refactoring #18 | review naming for 'writeToIORefAction' --> 'reader' refactoring #19 | use a 'Map.lookup' instead of 'List.filter' + pattern-match refactoring #20 | remove 'BlocksConsumed' wrapper refactoring #21 | generalize reader with polymorphic parametrism refactoring #22 | review pushNextBlocks indentation refactoring #23 | group case pattern matches using tuple refactoring #24 | remove 'Hash BlockHeader' from the block to inject refactoring #25 | use synchronization lock instead of computed times refactoring #26 | Move generation of duplicated blocks onto 'Arbitrary Blocks' refactoring #27 | remove 'chunkSizes' in a favor of inline random selection refactoring #28 | remove 'DeliveryMode' in favor of the most general case refactoring #29 | cleanup wrapper types refactoring #30 | generalize pushNextBlocks with parametric polymorphism refactoring #31 | rename pushNextBlocks to 'writer' refactoring #32 | define reader on Block instead of BlockHeaderHash refactoring #33 | replace old reader with reader' refactoring #34 | move creation of writer MVar inside writer action refactoring #35 | remove header hash from 'Blocks' refactoring #36 | rename 'consecutiveBlocks' into 'blocks' refactoring #37 | re-organize module to separate effectful logic from declarations refactoring #38 | move waiting logic into dedicated function refactoring #39 | move 'done' and 'readerChan' initialization into reader and writer refactoring #40 | use Millisecond instead of Second for shorter tests refactoring #41 | Move creation of blocks from writer to 'Arbitrary Blocks' [3] fix line width [3] aligning the code with other code changes [3] hlint suggestion [3] add .weeder.yaml to omit duplicateMaybes and groups to be announce during weeder execution [3] undo weeder ignore file plus remove pragma and unnecessary exports
[3] Adding ticking function test and downloading block logic [3] Block syncer working ok plus additional tests [3] Cleaning the code [3] cabal fix [3] Complete refactoring to the review [3] Final refactoring [3] cabal fix [3] hlint and weeding [3] add killing thread at the end of test [3] Replace IORef with MVar refactoring #1 | inline intermediate functions to see more clearly + remove debug console prints refactoring #2 | review indentation of 'where' clause refactoring #3 | inline loop and remove test intrumentation from test logic refactoring #4 | define generator for ticking args in a declarative manner refactoring #5 | purify tickingFunctionTest and make it a monadic property refactoring #6 | review naming in Arbitrary TickingArgs refactoring #7 | use guards in mkConsecutiveTestBlocks refactoring #8 | define single block generator from previous block refactoring #9 | use 'fromPreviousBlock' and start loop with an already initialize list refactoring #10 | purify mkConsecutiveTestBlocks by defining a test hash function refactoring #11 | switch argument positions in mkConsecutiveTestBlocks refactoring #12 | replace loop with built-in list 'iterate' refactoring #13 | define Arbitrary instance for creating consecutive blocks refactoring #14 | replace mkConsecutiveBlocks with a property parameter refactoring #15 | use 'newMVar' instead or 'newEmptyMVar' + 'putMVar' refactoring #16 | remove unecessary IO in 'writeToIORefAction' refactoring #17 | replace takeMVar + putMVar with modifyMVar refactoring #18 | review naming for 'writeToIORefAction' --> 'reader' refactoring #19 | use a 'Map.lookup' instead of 'List.filter' + pattern-match refactoring #20 | remove 'BlocksConsumed' wrapper refactoring #21 | generalize reader with polymorphic parametrism refactoring #22 | review pushNextBlocks indentation refactoring #23 | group case pattern matches using tuple refactoring #24 | remove 'Hash BlockHeader' from the block to inject refactoring #25 | use synchronization lock instead of computed times refactoring #26 | Move generation of duplicated blocks onto 'Arbitrary Blocks' refactoring #27 | remove 'chunkSizes' in a favor of inline random selection refactoring #28 | remove 'DeliveryMode' in favor of the most general case refactoring #29 | cleanup wrapper types refactoring #30 | generalize pushNextBlocks with parametric polymorphism refactoring #31 | rename pushNextBlocks to 'writer' refactoring #32 | define reader on Block instead of BlockHeaderHash refactoring #33 | replace old reader with reader' refactoring #34 | move creation of writer MVar inside writer action refactoring #35 | remove header hash from 'Blocks' refactoring #36 | rename 'consecutiveBlocks' into 'blocks' refactoring #37 | re-organize module to separate effectful logic from declarations refactoring #38 | move waiting logic into dedicated function refactoring #39 | move 'done' and 'readerChan' initialization into reader and writer refactoring #40 | use Millisecond instead of Second for shorter tests refactoring #41 | Move creation of blocks from writer to 'Arbitrary Blocks' [3] fix line width [3] aligning the code with other code changes [3] hlint suggestion [3] add .weeder.yaml to omit duplicateMaybes and groups to be announce during weeder execution [3] undo weeder ignore file plus remove pragma and unnecessary exports [3] remove not needed imports
33cd68f
to
a2f3c36
Compare
Issue Number
#3
Overview
Comments