From 84c49e45deca3ff7732b9bc39aad741ddf62fbf7 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Mon, 16 Dec 2019 09:52:43 +0100 Subject: [PATCH 1/4] Move 'BlockchainParameters' from Primitive.Model -> Primitive.Types 1. No reasons it's define in the Model rather than the types (although we should really break this gigantic .Types into smaller pieces) 2. Without this, finding a good home for 'ActiveSlotCoefficient' would have been awkward --- lib/core/src/Cardano/Wallet.hs | 6 +- lib/core/src/Cardano/Wallet/Api.hs | 3 +- lib/core/src/Cardano/Wallet/Api/Server.hs | 9 +-- lib/core/src/Cardano/Wallet/Network.hs | 3 +- .../src/Cardano/Wallet/Primitive/Model.hs | 67 +------------------ .../src/Cardano/Wallet/Primitive/Types.hs | 58 +++++++++++++++- .../Wallet/DummyTarget/Primitive/Types.hs | 3 +- .../test/unit/Cardano/Pool/MetricsSpec.hs | 4 +- lib/core/test/unit/Cardano/WalletSpec.hs | 3 +- .../exe/cardano-wallet-jormungandr.hs | 4 +- .../src/Cardano/Wallet/Jormungandr.hs | 3 +- .../Cardano/Wallet/Jormungandr/Api/Client.hs | 10 ++- .../src/Cardano/Wallet/Jormungandr/Network.hs | 3 +- lib/jormungandr/test/bench/Latency.hs | 4 +- lib/jormungandr/test/integration/Main.hs | 4 +- .../Cardano/Wallet/Jormungandr/NetworkSpec.hs | 9 ++- 16 files changed, 89 insertions(+), 104 deletions(-) diff --git a/lib/core/src/Cardano/Wallet.hs b/lib/core/src/Cardano/Wallet.hs index f89788ebaa9..538649192ab 100644 --- a/lib/core/src/Cardano/Wallet.hs +++ b/lib/core/src/Cardano/Wallet.hs @@ -187,15 +187,13 @@ import Cardano.Wallet.Primitive.Fee , computeFee ) import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) - , Wallet + ( Wallet , applyBlocks , availableUTxO , blockchainParameters , currentTip , getState , initWallet - , slotParams , updateState ) import Cardano.Wallet.Primitive.Types @@ -203,6 +201,7 @@ import Cardano.Wallet.Primitive.Types , AddressState (..) , Block (..) , BlockHeader (..) + , BlockchainParameters (..) , ChimericAccount (..) , Coin (..) , DelegationCertificate (..) @@ -233,6 +232,7 @@ import Cardano.Wallet.Primitive.Types , computeUtxoStatistics , dlgCertPoolId , log10 + , slotParams , slotRangeFromTimeRange , slotStartTime , syncProgressRelativeToTime diff --git a/lib/core/src/Cardano/Wallet/Api.hs b/lib/core/src/Cardano/Wallet/Api.hs index 5d64902e506..18bc6a37b9c 100644 --- a/lib/core/src/Cardano/Wallet/Api.hs +++ b/lib/core/src/Cardano/Wallet/Api.hs @@ -76,11 +76,10 @@ import Cardano.Wallet.Network ( NetworkLayer ) import Cardano.Wallet.Primitive.AddressDerivation ( Depth ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters ) import Cardano.Wallet.Primitive.Types ( AddressState , Block + , BlockchainParameters , PoolId , SortOrder (..) , SyncTolerance diff --git a/lib/core/src/Cardano/Wallet/Api/Server.hs b/lib/core/src/Cardano/Wallet/Api/Server.hs index 05dd1320199..ea0f6656e91 100644 --- a/lib/core/src/Cardano/Wallet/Api/Server.hs +++ b/lib/core/src/Cardano/Wallet/Api/Server.hs @@ -160,17 +160,12 @@ import Cardano.Wallet.Primitive.CoinSelection import Cardano.Wallet.Primitive.Fee ( Fee (..) ) import Cardano.Wallet.Primitive.Model - ( BlockchainParameters - , Wallet - , availableBalance - , currentTip - , getState - , totalBalance - ) + ( Wallet, availableBalance, currentTip, getState, totalBalance ) import Cardano.Wallet.Primitive.Types ( Address , AddressState , Block + , BlockchainParameters , ChimericAccount (..) , Coin (..) , Hash (..) diff --git a/lib/core/src/Cardano/Wallet/Network.hs b/lib/core/src/Cardano/Wallet/Network.hs index a98a1e570fb..f9751dc74cc 100644 --- a/lib/core/src/Cardano/Wallet/Network.hs +++ b/lib/core/src/Cardano/Wallet/Network.hs @@ -31,10 +31,9 @@ import Prelude import Cardano.BM.Trace ( Trace, logDebug, logError, logInfo, logWarning ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types ( BlockHeader (..) + , BlockchainParameters (..) , ChimericAccount (..) , EpochNo , Hash (..) diff --git a/lib/core/src/Cardano/Wallet/Primitive/Model.hs b/lib/core/src/Cardano/Wallet/Primitive/Model.hs index 278c632ce15..31d169c257f 100644 --- a/lib/core/src/Cardano/Wallet/Primitive/Model.hs +++ b/lib/core/src/Cardano/Wallet/Primitive/Model.hs @@ -34,12 +34,11 @@ module Cardano.Wallet.Primitive.Model ( -- * Type Wallet - , BlockchainParameters (..) -- * Construction & Modification + , FilteredBlock (..) , initWallet , updateState - , FilteredBlock (..) , applyBlock , applyBlocks , unsafeInitWallet @@ -53,9 +52,6 @@ module Cardano.Wallet.Primitive.Model , availableUTxO , utxo , blockchainParameters - - -- * Auxiliary - , slotParams ) where import Prelude @@ -66,16 +62,11 @@ import Cardano.Wallet.Primitive.Types ( Address (..) , Block (..) , BlockHeader (..) + , BlockchainParameters (..) , ChimericAccount (..) , DelegationCertificate (..) , Direction (..) , Dom (..) - , EpochLength (..) - , FeePolicy (..) - , Hash (..) - , SlotLength (..) - , SlotParameters (SlotParameters) - , StartTime (..) , Tx (..) , TxIn (..) , TxMeta (..) @@ -97,8 +88,6 @@ import Control.Monad.Extra ( mapMaybeM ) import Control.Monad.Trans.State.Strict ( State, evalState, runState, state ) -import Data.ByteArray.Encoding - ( Base (Base16), convertToBase ) import Data.Functor ( (<&>) ) import Data.Generics.Internal.VL.Lens @@ -113,12 +102,8 @@ import Data.Quantity ( Quantity (..) ) import Data.Set ( Set ) -import Data.Text.Class - ( toText ) -import Data.Word - ( Word16, Word32 ) import Fmt - ( Buildable (..), blockListF', indentF ) + ( Buildable (..), indentF ) import GHC.Generics ( Generic ) import Numeric.Natural @@ -127,7 +112,6 @@ import Numeric.Natural import qualified Data.List.NonEmpty as NE import qualified Data.Map as Map import qualified Data.Set as Set -import qualified Data.Text.Encoding as T {------------------------------------------------------------------------------- Type @@ -193,51 +177,6 @@ instance Buildable s => Buildable (Wallet s) where <> indentF 4 ("UTxO: " <> build u) <> indentF 4 (build s) -data BlockchainParameters = BlockchainParameters - { getGenesisBlockHash :: Hash "Genesis" - -- ^ Hash of the very first block - , getGenesisBlockDate :: StartTime - -- ^ Start time of the chain. - , getFeePolicy :: FeePolicy - -- ^ Policy regarding transaction fee. - , getSlotLength :: SlotLength - -- ^ Length, in seconds, of a slot. - , getEpochLength :: EpochLength - -- ^ Number of slots in a single epoch. - , getTxMaxSize :: Quantity "byte" Word16 - -- ^ Maximum size of a transaction (soft or hard limit). - , getEpochStability :: Quantity "block" Word32 - -- ^ Length of the suffix of the chain considered unstable - } deriving (Generic, Show, Eq) - -instance NFData BlockchainParameters - -instance Buildable BlockchainParameters where - build bp = blockListF' "" id - [ "Genesis block hash: " <> genesisF (getGenesisBlockHash bp) - , "Genesis block date: " <> startTimeF (getGenesisBlockDate bp) - , "Fee policy: " <> feePolicyF (getFeePolicy bp) - , "Slot length: " <> slotLengthF (getSlotLength bp) - , "Epoch length: " <> epochLengthF (getEpochLength bp) - , "Tx max size: " <> txMaxSizeF (getTxMaxSize bp) - , "Epoch stability: " <> epochStabilityF (getEpochStability bp) - ] - where - genesisF = build . T.decodeUtf8 . convertToBase Base16 . getHash - startTimeF (StartTime s) = build s - feePolicyF = build . toText - slotLengthF (SlotLength s) = build s - epochLengthF (EpochLength s) = build s - txMaxSizeF (Quantity s) = build s - epochStabilityF (Quantity s) = build s - -slotParams :: BlockchainParameters -> SlotParameters -slotParams bp = - SlotParameters - (bp ^. #getEpochLength) - (bp ^. #getSlotLength) - (bp ^. #getGenesisBlockDate) - {------------------------------------------------------------------------------- Construction & Modification -------------------------------------------------------------------------------} diff --git a/lib/core/src/Cardano/Wallet/Primitive/Types.hs b/lib/core/src/Cardano/Wallet/Primitive/Types.hs index 05c393f6698..43c257edad7 100644 --- a/lib/core/src/Cardano/Wallet/Primitive/Types.hs +++ b/lib/core/src/Cardano/Wallet/Primitive/Types.hs @@ -83,6 +83,10 @@ module Cardano.Wallet.Primitive.Types , computeUtxoStatistics , log10 + -- * BlockchainParameters + , BlockchainParameters (..) + , slotParams + -- * Slotting , SyncProgress(..) , SyncTolerance(..) @@ -218,7 +222,7 @@ import Data.Text.Class import Data.Time.Clock ( NominalDiffTime, UTCTime, addUTCTime, diffUTCTime ) import Data.Word - ( Word32, Word64 ) + ( Word16, Word32, Word64 ) import Data.Word.Odd ( Word31 ) import Fmt @@ -1072,6 +1076,58 @@ computeUtxoStatistics btype utxos = (^!) :: Word64 -> Word64 -> Word64 (^!) = (^) +{------------------------------------------------------------------------------- + Blockchain Parameters +-------------------------------------------------------------------------------} + +data BlockchainParameters = BlockchainParameters + { getGenesisBlockHash :: Hash "Genesis" + -- ^ Hash of the very first block + , getGenesisBlockDate :: StartTime + -- ^ Start time of the chain. + , getFeePolicy :: FeePolicy + -- ^ Policy regarding transaction fee. + , getSlotLength :: SlotLength + -- ^ Length, in seconds, of a slot. + , getEpochLength :: EpochLength + -- ^ Number of slots in a single epoch. + , getTxMaxSize :: Quantity "byte" Word16 + -- ^ Maximum size of a transaction (soft or hard limit). + , getEpochStability :: Quantity "block" Word32 + -- ^ Length of the suffix of the chain considered unstable + } deriving (Generic, Show, Eq) + +instance NFData BlockchainParameters + +instance Buildable BlockchainParameters where + build bp = blockListF' "" id + [ "Genesis block hash: " <> genesisF (getGenesisBlockHash bp) + , "Genesis block date: " <> startTimeF (getGenesisBlockDate + (bp :: BlockchainParameters)) + , "Fee policy: " <> feePolicyF (getFeePolicy bp) + , "Slot length: " <> slotLengthF (getSlotLength + (bp :: BlockchainParameters)) + , "Epoch length: " <> epochLengthF (getEpochLength + (bp :: BlockchainParameters)) + , "Tx max size: " <> txMaxSizeF (getTxMaxSize bp) + , "Epoch stability: " <> epochStabilityF (getEpochStability bp) + ] + where + genesisF = build . T.decodeUtf8 . convertToBase Base16 . getHash + startTimeF (StartTime s) = build s + feePolicyF = build . toText + slotLengthF (SlotLength s) = build s + epochLengthF (EpochLength s) = build s + txMaxSizeF (Quantity s) = build s + epochStabilityF (Quantity s) = build s + +slotParams :: BlockchainParameters -> SlotParameters +slotParams bp = + SlotParameters + (bp ^. #getEpochLength) + (bp ^. #getSlotLength) + (bp ^. #getGenesisBlockDate) + {------------------------------------------------------------------------------- Slotting -------------------------------------------------------------------------------} diff --git a/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs b/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs index 60007fad2b0..33545474065 100644 --- a/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs +++ b/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs @@ -15,11 +15,10 @@ module Cardano.Wallet.DummyTarget.Primitive.Types import Prelude -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types ( Block (..) , BlockHeader (..) + , BlockchainParameters (..) , Coin (..) , EpochLength (..) , FeePolicy (..) diff --git a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs index 402b0d57b0b..738e4fde540 100644 --- a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs +++ b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs @@ -47,10 +47,9 @@ import Cardano.Wallet.Network , NetworkLayer (..) , NextBlocksResult (..) ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..), slotParams ) import Cardano.Wallet.Primitive.Types ( BlockHeader (..) + , BlockchainParameters (..) , Coin (..) , EpochLength (..) , Hash (..) @@ -61,6 +60,7 @@ import Cardano.Wallet.Primitive.Types , flatSlot , flatSlot , fromFlatSlot + , slotParams , slotSucc ) import Cardano.Wallet.Unsafe diff --git a/lib/core/test/unit/Cardano/WalletSpec.hs b/lib/core/test/unit/Cardano/WalletSpec.hs index 7c10f956ad3..5ce040e8ad3 100644 --- a/lib/core/test/unit/Cardano/WalletSpec.hs +++ b/lib/core/test/unit/Cardano/WalletSpec.hs @@ -55,10 +55,9 @@ import Cardano.Wallet.Primitive.AddressDiscovery ) import Cardano.Wallet.Primitive.CoinSelection ( CoinSelection (..) ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types ( Address (..) + , BlockchainParameters (..) , ChimericAccount (..) , Coin (..) , Direction (..) diff --git a/lib/jormungandr/exe/cardano-wallet-jormungandr.hs b/lib/jormungandr/exe/cardano-wallet-jormungandr.hs index e66aa03bd30..7663c227530 100644 --- a/lib/jormungandr/exe/cardano-wallet-jormungandr.hs +++ b/lib/jormungandr/exe/cardano-wallet-jormungandr.hs @@ -72,10 +72,8 @@ import Cardano.Wallet.Logging ( transformTextTrace ) import Cardano.Wallet.Primitive.AddressDerivation ( NetworkDiscriminant (..) ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters ) import Cardano.Wallet.Primitive.Types - ( Hash (..), SyncTolerance ) + ( BlockchainParameters, Hash (..), SyncTolerance ) import Cardano.Wallet.Version ( gitRevision, showFullVersion, version ) import Control.Applicative diff --git a/lib/jormungandr/src/Cardano/Wallet/Jormungandr.hs b/lib/jormungandr/src/Cardano/Wallet/Jormungandr.hs index 718b43021df..c9ee5da80ff 100644 --- a/lib/jormungandr/src/Cardano/Wallet/Jormungandr.hs +++ b/lib/jormungandr/src/Cardano/Wallet/Jormungandr.hs @@ -89,12 +89,11 @@ import Cardano.Wallet.Primitive.AddressDiscovery.Random ( RndState ) import Cardano.Wallet.Primitive.AddressDiscovery.Sequential ( SeqState ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types ( Address , Block , BlockHeader (..) + , BlockchainParameters (..) , ChimericAccount , Hash (..) , SyncTolerance diff --git a/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs b/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs index ed872359441..f6c6b57c85e 100644 --- a/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs +++ b/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs @@ -68,10 +68,14 @@ import Cardano.Wallet.Network , ErrNetworkUnavailable (..) , ErrPostTx (..) ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types - ( Block (..), BlockHeader (..), Hash (..), SealedTx, SlotLength (..) ) + ( Block (..) + , BlockHeader (..) + , BlockchainParameters (..) + , Hash (..) + , SealedTx + , SlotLength (..) + ) import Control.Arrow ( left ) import Control.Exception diff --git a/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Network.hs b/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Network.hs index 8af16b753d5..a44fa02b02d 100644 --- a/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Network.hs +++ b/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Network.hs @@ -117,10 +117,9 @@ import Cardano.Wallet.Network.BlockHeaders ) import Cardano.Wallet.Network.Ports ( PortNumber, getRandomPort, waitForPort ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types ( BlockHeader (..) + , BlockchainParameters (..) , ChimericAccount (..) , EpochNo , Hash (..) diff --git a/lib/jormungandr/test/bench/Latency.hs b/lib/jormungandr/test/bench/Latency.hs index cc651c20d43..d88eb1060a2 100644 --- a/lib/jormungandr/test/bench/Latency.hs +++ b/lib/jormungandr/test/bench/Latency.hs @@ -49,10 +49,8 @@ import Cardano.Wallet.Jormungandr.Network ( JormungandrBackend (..) ) import Cardano.Wallet.Primitive.AddressDerivation ( NetworkDiscriminant (..) ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types - ( SyncTolerance (..) ) + ( BlockchainParameters (..), SyncTolerance (..) ) import Control.Concurrent.Async ( race ) import Control.Concurrent.MVar diff --git a/lib/jormungandr/test/integration/Main.hs b/lib/jormungandr/test/integration/Main.hs index d1d3303daa7..72a33d43e2a 100644 --- a/lib/jormungandr/test/integration/Main.hs +++ b/lib/jormungandr/test/integration/Main.hs @@ -42,10 +42,8 @@ import Cardano.Wallet.Primitive.AddressDerivation ( NetworkDiscriminant (..) ) import Cardano.Wallet.Primitive.Fee ( FeePolicy (..) ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types - ( SyncTolerance (..) ) + ( BlockchainParameters (..), SyncTolerance (..) ) import Control.Concurrent.Async ( race ) import Control.Concurrent.MVar diff --git a/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs b/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs index 306d966df3d..daa0392ea5b 100644 --- a/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs +++ b/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs @@ -24,10 +24,13 @@ import Cardano.Wallet.Network ( Cursor, ErrGetBlock (..), NetworkLayer (..), NextBlocksResult (..) ) import Cardano.Wallet.Network.BlockHeaders ( emptyBlockHeaders ) -import Cardano.Wallet.Primitive.Model - ( BlockchainParameters (..) ) import Cardano.Wallet.Primitive.Types - ( BlockHeader (..), Hash (..), SlotId (..), SlotNo (unSlotNo) ) + ( BlockHeader (..) + , BlockchainParameters (..) + , Hash (..) + , SlotId (..) + , SlotNo (unSlotNo) + ) import Control.Concurrent.MVar.Lifted ( newMVar ) import Control.Monad.Fail From 3eb58962b1d45f2408b103ce382a954e0a93fa91 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Mon, 16 Dec 2019 11:09:38 +0100 Subject: [PATCH 2/4] add 'ActiveSlotCoefficient' to blockchain parameters --- lib/core/src/Cardano/Wallet/DB/Sqlite.hs | 4 +++ lib/core/src/Cardano/Wallet/DB/Sqlite/TH.hs | 25 +++++++------- .../src/Cardano/Wallet/Primitive/Types.hs | 26 +++++++++++---- .../Wallet/DummyTarget/Primitive/Types.hs | 4 ++- .../test/unit/Cardano/Pool/MetricsSpec.hs | 1 + .../Cardano/Wallet/Jormungandr/Api/Client.hs | 33 ++++++++++++++----- .../Cardano/Wallet/Jormungandr/NetworkSpec.hs | 1 + 7 files changed, 65 insertions(+), 29 deletions(-) diff --git a/lib/core/src/Cardano/Wallet/DB/Sqlite.hs b/lib/core/src/Cardano/Wallet/DB/Sqlite.hs index 3724eb71ab2..b4f473d5964 100644 --- a/lib/core/src/Cardano/Wallet/DB/Sqlite.hs +++ b/lib/core/src/Cardano/Wallet/DB/Sqlite.hs @@ -555,6 +555,8 @@ mkCheckpointEntity wid wal = , checkpointEpochLength = coerce (bp ^. #getEpochLength) , checkpointTxMaxSize = coerce (bp ^. #getTxMaxSize) , checkpointEpochStability = coerce (bp ^. #getEpochStability) + , checkpointActiveSlotCoeff = + W.unActiveSlotCoefficient (bp ^. #getActiveSlotCoefficient) } utxo = [ UTxO wid sl (TxId input) ix addr coin @@ -589,6 +591,7 @@ checkpointFromEntity cp utxo s = epochLength txMaxSize epochStability + activeSlotCoeff ) = cp header = (W.BlockHeader slot (Quantity bh) headerHash parentHeaderHash) utxo' = W.UTxO . Map.fromList $ @@ -603,6 +606,7 @@ checkpointFromEntity cp utxo s = , getEpochLength = W.EpochLength epochLength , getTxMaxSize = Quantity txMaxSize , getEpochStability = Quantity epochStability + , getActiveSlotCoefficient = W.ActiveSlotCoefficient activeSlotCoeff } mkTxHistory diff --git a/lib/core/src/Cardano/Wallet/DB/Sqlite/TH.hs b/lib/core/src/Cardano/Wallet/DB/Sqlite/TH.hs index 323a589a759..bef069856e2 100644 --- a/lib/core/src/Cardano/Wallet/DB/Sqlite/TH.hs +++ b/lib/core/src/Cardano/Wallet/DB/Sqlite/TH.hs @@ -125,18 +125,19 @@ TxOut -- A checkpoint for a given wallet is referred to by (wallet_id, slot). -- Volatile checkpoint data such as AD state will refer to this table. Checkpoint - checkpointWalletId W.WalletId sql=wallet_id - checkpointSlot W.SlotId sql=slot - checkpointHeaderHash BlockId sql=header_hash - checkpointParentHash BlockId sql=parent_header_hash - checkpointBlockHeight Word32 sql=block_height - checkpointGenesisHash BlockId sql=genesis_hash - checkpointGenesisStart UTCTime sql=genesis_start - checkpointFeePolicy W.FeePolicy sql=fee_policy - checkpointSlotLength Word64 sql=slot_length - checkpointEpochLength Word32 sql=epoch_length - checkpointTxMaxSize Word16 sql=tx_max_size - checkpointEpochStability Word32 sql=epoch_stability + checkpointWalletId W.WalletId sql=wallet_id + checkpointSlot W.SlotId sql=slot + checkpointHeaderHash BlockId sql=header_hash + checkpointParentHash BlockId sql=parent_header_hash + checkpointBlockHeight Word32 sql=block_height + checkpointGenesisHash BlockId sql=genesis_hash + checkpointGenesisStart UTCTime sql=genesis_start + checkpointFeePolicy W.FeePolicy sql=fee_policy + checkpointSlotLength Word64 sql=slot_length + checkpointEpochLength Word32 sql=epoch_length + checkpointTxMaxSize Word16 sql=tx_max_size + checkpointEpochStability Word32 sql=epoch_stability + checkpointActiveSlotCoeff Double sql=active_slot_coeff Primary checkpointWalletId checkpointSlot Foreign Wallet checkpoint checkpointWalletId ! ON DELETE CASCADE diff --git a/lib/core/src/Cardano/Wallet/Primitive/Types.hs b/lib/core/src/Cardano/Wallet/Primitive/Types.hs index 43c257edad7..e775ebe4485 100644 --- a/lib/core/src/Cardano/Wallet/Primitive/Types.hs +++ b/lib/core/src/Cardano/Wallet/Primitive/Types.hs @@ -46,7 +46,6 @@ module Cardano.Wallet.Primitive.Types , TxWitness(..) , SealedTx (..) , TransactionInfo (..) - , FeePolicy (..) , UnsignedTx (..) , txIns , isPending @@ -85,15 +84,20 @@ module Cardano.Wallet.Primitive.Types -- * BlockchainParameters , BlockchainParameters (..) + , ActiveSlotCoefficient (..) + , EpochLength (..) + , EpochNo (..) + , FeePolicy (..) + , SlotId (..) + , SlotLength (..) + , SlotNo (..) + , StartTime (..) , slotParams -- * Slotting , SyncProgress(..) , SyncTolerance(..) , mkSyncTolerance - , SlotId (..) - , SlotNo (..) - , EpochNo (..) , unsafeEpochNo , epochStartTime , epochPred @@ -101,9 +105,6 @@ module Cardano.Wallet.Primitive.Types , epochCeiling , epochFloor , SlotParameters (..) - , SlotLength (..) - , EpochLength (..) - , StartTime (..) , syncProgress , syncProgressRelativeToTime , flatSlot @@ -1095,6 +1096,9 @@ data BlockchainParameters = BlockchainParameters -- ^ Maximum size of a transaction (soft or hard limit). , getEpochStability :: Quantity "block" Word32 -- ^ Length of the suffix of the chain considered unstable + , getActiveSlotCoefficient :: ActiveSlotCoefficient + -- ^ In Genesis/Praos, corresponds to the % of active slots + -- (i.e. slots for which someone can be elected as leader). } deriving (Generic, Show, Eq) instance NFData BlockchainParameters @@ -1111,6 +1115,7 @@ instance Buildable BlockchainParameters where (bp :: BlockchainParameters)) , "Tx max size: " <> txMaxSizeF (getTxMaxSize bp) , "Epoch stability: " <> epochStabilityF (getEpochStability bp) + , "Active slot coeff: " <> build (getActiveSlotCoefficient bp) ] where genesisF = build . T.decodeUtf8 . convertToBase Base16 . getHash @@ -1121,6 +1126,13 @@ instance Buildable BlockchainParameters where txMaxSizeF (Quantity s) = build s epochStabilityF (Quantity s) = build s +newtype ActiveSlotCoefficient + = ActiveSlotCoefficient { unActiveSlotCoefficient :: Double } + deriving stock (Generic, Eq, Show) + deriving newtype (Buildable) + +instance NFData ActiveSlotCoefficient + slotParams :: BlockchainParameters -> SlotParameters slotParams bp = SlotParameters diff --git a/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs b/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs index 33545474065..80f7f593974 100644 --- a/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs +++ b/lib/core/test/shared/Cardano/Wallet/DummyTarget/Primitive/Types.hs @@ -16,7 +16,8 @@ module Cardano.Wallet.DummyTarget.Primitive.Types import Prelude import Cardano.Wallet.Primitive.Types - ( Block (..) + ( ActiveSlotCoefficient (..) + , Block (..) , BlockHeader (..) , BlockchainParameters (..) , Coin (..) @@ -75,6 +76,7 @@ genesisParameters = BlockchainParameters , getEpochLength = EpochLength 21600 , getTxMaxSize = Quantity 8192 , getEpochStability = Quantity 2160 + , getActiveSlotCoefficient = ActiveSlotCoefficient 1 } diff --git a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs index 738e4fde540..5946fd957d8 100644 --- a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs +++ b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs @@ -426,6 +426,7 @@ mockBlockchainParameters = BlockchainParameters , getEpochLength = error "mockBlockchainParameters: getEpochLength" , getTxMaxSize = error "mockBlockchainParameters: getTxMaxSize" , getEpochStability = error "mockBlockchainParameters: getEpochStability" + , getActiveSlotCoefficient = error "mockBlockchainParameters: getActiveSlotCoefficient" } header0 :: BlockHeader diff --git a/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs b/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs index f6c6b57c85e..504f01cc561 100644 --- a/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs +++ b/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Api/Client.hs @@ -59,7 +59,12 @@ import Cardano.Wallet.Jormungandr.Api import Cardano.Wallet.Jormungandr.Api.Types ( AccountId (..), AccountState, BlockId (..), StakeApiResponse ) import Cardano.Wallet.Jormungandr.Binary - ( ConfigParam (..), Fragment (..), convertBlock, overrideFeePolicy ) + ( ConfigParam (..) + , Fragment (..) + , Milli (..) + , convertBlock + , overrideFeePolicy + ) import Cardano.Wallet.Jormungandr.Compatibility ( softTxMaxSize ) import Cardano.Wallet.Network @@ -69,7 +74,8 @@ import Cardano.Wallet.Network , ErrPostTx (..) ) import Cardano.Wallet.Primitive.Types - ( Block (..) + ( ActiveSlotCoefficient (..) + , Block (..) , BlockHeader (..) , BlockchainParameters (..) , Hash (..) @@ -251,13 +257,13 @@ mkJormungandrClient mgr baseUrl = JormungandrClient SlotDuration x -> Just x _ -> Nothing - let mblock0Date = mapMaybe getBlock0Date params + let mblock0T = mapMaybe getBlock0T params where - getBlock0Date = \case + getBlock0T = \case Block0Date x -> Just x _ -> Nothing - let mepochLength = mapMaybe getSlotsPerEpoch params + let mepLength = mapMaybe getSlotsPerEpoch params where getSlotsPerEpoch = \case SlotsPerEpoch x -> Just x @@ -269,20 +275,29 @@ mkJormungandrClient mgr baseUrl = JormungandrClient EpochStabilityDepth x -> Just x _ -> Nothing - case (mpolicy, mduration, mblock0Date, mepochLength, mStability) of - ([policy],[duration],[block0Date], [epochLength], [stability]) -> + let mcoeff = mapMaybe getCoeff params + where + getCoeff = \case + ConsensusGenesisPraosParamF (Milli f) -> + Just $ ActiveSlotCoefficient $ fromIntegral f / 1000 + _ -> Nothing + + + case (mpolicy, mduration, mblock0T, mepLength, mStability, mcoeff) of + ([policy],[duration],[block0T], [epLength], [stability],[coeff]) -> return ( jblock , BlockchainParameters { getGenesisBlockHash = block0 - , getGenesisBlockDate = block0Date + , getGenesisBlockDate = block0T , getFeePolicy = case mperCertFee of [override] -> overrideFeePolicy policy override _ -> policy - , getEpochLength = epochLength + , getEpochLength = epLength , getSlotLength = SlotLength duration , getTxMaxSize = softTxMaxSize , getEpochStability = stability + , getActiveSlotCoefficient = coeff } ) _ -> diff --git a/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs b/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs index daa0392ea5b..f4d3012e056 100644 --- a/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs +++ b/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/NetworkSpec.hs @@ -393,6 +393,7 @@ mockJormungandrClient logLine = JormungandrClient , getEpochLength = error "mock bp" , getTxMaxSize = error "mock bp" , getEpochStability = Quantity (fromIntegral k) + , getActiveSlotCoefficient = error "mock bp" }) , postMessage = \_ -> error "mock postMessage" From 7c7dd0a91194a9283ffe1026a97d366373547186 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Mon, 16 Dec 2019 11:29:17 +0100 Subject: [PATCH 3/4] Add extra unit test to pools perf illustrating the influence of f Current fails, as expected: 1) Cardano.Pool.Metrics.calculatePerformances, golden test cases, 100% stake, coeff=0.1, producing 1/10 blocks => p=1.0 expected: Just 1.0 but got: Just 0.1 --- .../test/unit/Cardano/Pool/MetricsSpec.hs | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs index 5946fd957d8..4aa2d7b79dc 100644 --- a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs +++ b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs @@ -220,29 +220,35 @@ prop_performancesBounded01 mStake_ mProd_ (NonNegative emptySlots) = performanceGoldens :: Spec performanceGoldens = do - it "50% stake, producing 8/8 blocks => performance=1.0" $ do - let stake = mkStake [ (poolA, 1), (poolB, 1) ] - let production = mkProduction [ (poolA, 8), (poolB, 0) ] - let performances = calculatePerformance 8 stake production + it "50% stake, coeff=1.0, producing 8/8 blocks => p=1.0" $ do + let stake = mkStake [ (poolA, 1), (poolB, 1) ] + let production = mkProduction [ (poolA, 8), (poolB, 0) ] + let performances = calculatePerformance 1.0 8 stake production Map.lookup poolA performances `shouldBe` (Just 1) - it "50% stake, producing 4/8 blocks => performance=1.0" $ do - let stake = mkStake [ (poolA, 1), (poolB, 1) ] - let production = mkProduction [ (poolA, 4), (poolB, 0) ] - let performances = calculatePerformance 8 stake production + it "50% stake, coeff=1.0, producing 4/8 blocks => p=1.0" $ do + let stake = mkStake [ (poolA, 1), (poolB, 1) ] + let production = mkProduction [ (poolA, 4), (poolB, 0) ] + let performances = calculatePerformance 1.0 8 stake production Map.lookup poolA performances `shouldBe` (Just 1) - it "50% stake, producing 2/8 blocks => performance=0.5" $ do - let stake = mkStake [ (poolA, 1), (poolB, 1) ] - let production = mkProduction [ (poolA, 2), (poolB, 0) ] - let performances = calculatePerformance 8 stake production + it "50% stake, coeff=1.0, producing 2/8 blocks => p=0.5" $ do + let stake = mkStake [ (poolA, 1), (poolB, 1) ] + let production = mkProduction [ (poolA, 2), (poolB, 0) ] + let performances = calculatePerformance 1.0 8 stake production Map.lookup poolA performances `shouldBe` (Just 0.5) - it "50% stake, producing 0/8 blocks => performance=0.0" $ do - let stake = mkStake [ (poolA, 1), (poolB, 1) ] - let production = mkProduction [ (poolA, 0), (poolB, 0) ] - let performances = calculatePerformance 8 stake production + it "50% stake, coeff=1.0, producing 0/8 blocks => p=0.0" $ do + let stake = mkStake [ (poolA, 1), (poolB, 1) ] + let production = mkProduction [ (poolA, 0), (poolB, 0) ] + let performances = calculatePerformance 1.0 8 stake production Map.lookup poolA performances `shouldBe` (Just 0) + + it "100% stake, coeff=0.1, producing 1/10 blocks => p=1.0" $ do + let stake = mkStake [ (poolA, 1), (poolB, 0) ] + let production = mkProduction [ (poolA, 1), (poolB, 0) ] + let performances = calculatePerformance 0.1 10 stake production + Map.lookup poolA performances `shouldBe` (Just 1.0) where poolA = PoolId "athena" poolB = PoolId "nemesis" From cb780de860cec5f43509429625001b9179351ec1 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Mon, 16 Dec 2019 11:24:02 +0100 Subject: [PATCH 4/4] take 'active slot coefficient' into account in the apparent performance calculation --- lib/core/src/Cardano/Pool/Metrics.hs | 20 ++++++++++++------- .../src/Cardano/Wallet/Primitive/Types.hs | 2 +- .../test/unit/Cardano/Pool/MetricsSpec.hs | 15 ++++++++++---- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/core/src/Cardano/Pool/Metrics.hs b/lib/core/src/Cardano/Pool/Metrics.hs index bb2a8f02fb2..ad4133e55f7 100644 --- a/lib/core/src/Cardano/Pool/Metrics.hs +++ b/lib/core/src/Cardano/Pool/Metrics.hs @@ -70,7 +70,8 @@ import Cardano.Wallet.Network , staticBlockchainParameters ) import Cardano.Wallet.Primitive.Types - ( BlockHeader (..) + ( ActiveSlotCoefficient (..) + , BlockHeader (..) , EpochLength (..) , EpochNo (..) , PoolId (..) @@ -304,7 +305,7 @@ newStakePoolLayer tr db@DBLayer{..} nl metadataDir = StakePoolLayer else do let sl = prodTip ^. #slotId - perfs <- liftIO $ readPoolsPerformances db epochLength sl + perfs <- liftIO $ readPoolsPerformances db activeSlotCoeff epochLength sl combineWith (pure . sortByPerformance) distr (count prod) perfs readPoolProductionTip = readPoolProductionCursor 1 <&> \case @@ -331,6 +332,7 @@ newStakePoolLayer tr db@DBLayer{..} nl metadataDir = StakePoolLayer (block0, bp) = staticBlockchainParameters nl epochLength = bp ^. #getEpochLength + activeSlotCoeff = bp ^. #getActiveSlotCoefficient combineWith :: ([(StakePool, [PoolOwner])] -> IO [(StakePool, [PoolOwner])]) @@ -401,11 +403,13 @@ readNewcomers DBLayer{..} elders avg = do readPoolsPerformances :: DBLayer m + -> ActiveSlotCoefficient -> EpochLength -> SlotId -> m (Map PoolId Double) -readPoolsPerformances DBLayer{..} (EpochLength el) tip = do +readPoolsPerformances DBLayer{..} activeSlotCoeff (EpochLength el) tip = do atomically $ fmap avg $ forM historicalEpochs $ \ep -> calculatePerformance + activeSlotCoeff (slotsInEpoch ep) <$> (Map.fromList <$> readStakeDistribution ep) <*> (count <$> readPoolProduction ep) @@ -442,10 +446,11 @@ readPoolsPerformances DBLayer{..} (EpochLength el) tip = do -- is a 'Double' between 0 and 1 as: -- -- @ --- p = n / N * S / s +-- p = n / (f * N) * S / s -- where -- n = number of blocks produced in an epoch e -- N = number of slots in e +-- f = active slot coeff, i.e. % of slots for which a leader can be elected. -- s = stake owned by the pool in e -- S = total stake delegated to pools in e -- @ @@ -454,11 +459,12 @@ readPoolsPerformances DBLayer{..} (EpochLength el) tip = do -- practice, be greater than 1 if a stake pool produces more than it is -- expected. calculatePerformance - :: Int + :: ActiveSlotCoefficient + -> Int -> Map PoolId (Quantity "lovelace" Word64) -> Map PoolId (Quantity "block" Word64) -> Map PoolId Double -calculatePerformance nTotal mStake mProd = +calculatePerformance (ActiveSlotCoefficient f) nTotal mStake mProd = let stakeButNotProd = traverseMissing $ \_ _ -> 0 prodButNoStake = dropMissing @@ -466,7 +472,7 @@ calculatePerformance nTotal mStake mProd = if (nTotal == 0 || s == Quantity 0) then 0 else - min 1 ((double n / fromIntegral nTotal) * (sTotal / double s)) + min 1 ((double n / (f * fromIntegral nTotal)) * (sTotal / double s)) in Map.merge stakeButNotProd diff --git a/lib/core/src/Cardano/Wallet/Primitive/Types.hs b/lib/core/src/Cardano/Wallet/Primitive/Types.hs index e775ebe4485..ae48f0ed967 100644 --- a/lib/core/src/Cardano/Wallet/Primitive/Types.hs +++ b/lib/core/src/Cardano/Wallet/Primitive/Types.hs @@ -1129,7 +1129,7 @@ instance Buildable BlockchainParameters where newtype ActiveSlotCoefficient = ActiveSlotCoefficient { unActiveSlotCoefficient :: Double } deriving stock (Generic, Eq, Show) - deriving newtype (Buildable) + deriving newtype (Buildable, Num, Fractional) instance NFData ActiveSlotCoefficient diff --git a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs index 4aa2d7b79dc..8a139884bb6 100644 --- a/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs +++ b/lib/core/test/unit/Cardano/Pool/MetricsSpec.hs @@ -48,7 +48,8 @@ import Cardano.Wallet.Network , NextBlocksResult (..) ) import Cardano.Wallet.Primitive.Types - ( BlockHeader (..) + ( ActiveSlotCoefficient (..) + , BlockHeader (..) , BlockchainParameters (..) , Coin (..) , EpochLength (..) @@ -195,11 +196,12 @@ prop_combineIsLeftBiased mStake_ mProd_ mPerf_ = -- | Performances are always positive numbers prop_performancesBounded01 - :: Map (LowEntropy PoolId) (Quantity "lovelace" Word64) + :: ActiveSlotCoefficient + -> Map (LowEntropy PoolId) (Quantity "lovelace" Word64) -> Map (LowEntropy PoolId) (Quantity "block" Word64) -> (NonNegative Int) -> Property -prop_performancesBounded01 mStake_ mProd_ (NonNegative emptySlots) = +prop_performancesBounded01 coeff mStake_ mProd_ (NonNegative emptySlots) = all (between 0 1) performances & counterexample (show performances) & classify (all (== 0) performances) "all null" @@ -208,7 +210,7 @@ prop_performancesBounded01 mStake_ mProd_ (NonNegative emptySlots) = mProd = Map.mapKeys getLowEntropy mProd_ performances :: [Double] - performances = Map.elems $ calculatePerformance slots mStake mProd + performances = Map.elems $ calculatePerformance coeff slots mStake mProd slots :: Int slots = emptySlots + @@ -486,6 +488,11 @@ instance Arbitrary (Quantity "lovelace" Word64) where arbitrary = Quantity . fromIntegral . unLovelace <$> (arbitrary @Lovelace) shrink (Quantity x) = map Quantity $ shrink x +instance Arbitrary ActiveSlotCoefficient where + arbitrary = ActiveSlotCoefficient <$> choose (0.001, 1.0) + shrink (ActiveSlotCoefficient f) = ActiveSlotCoefficient + <$> filter (\f' -> f' > 0.001 && f' <= 1.0) (shrink f) + -- TODO: Move to a shared location for Arbitrary newtypes newtype Lovelace = Lovelace { unLovelace :: Word64 } instance Arbitrary Lovelace where