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

Getting minimum utxo #1894

Merged
merged 8 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/byron/bench/Restore.hs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ import Cardano.Wallet.Primitive.Types
, Block (..)
, BlockHeader (..)
, ChimericAccount
, Coin (..)
, GenesisParameters (..)
, NetworkParameters (..)
, SlotId (..)
Expand Down Expand Up @@ -425,6 +426,7 @@ withBenchDBLayer tr action =
migrationDefaultValues = Sqlite.DefaultFieldValues
{ Sqlite.defaultActiveSlotCoefficient = 1
, Sqlite.defaultDesiredNumberOfPool = 0
, Sqlite.defaultMinimumUTxOValue = Coin 0
}

-- This tweaks the DB support the AnyAddressState.
Expand Down
2 changes: 2 additions & 0 deletions lib/byron/src/Cardano/Wallet/Byron.hs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ serveWallet
getActiveSlotCoefficient gp
, defaultDesiredNumberOfPool =
desiredNumberOfStakePools (protocolParameters np)
, defaultMinimumUTxOValue =
minimumUTxOvalue (protocolParameters np)
}
)
databaseDir
Expand Down
2 changes: 2 additions & 0 deletions lib/byron/src/Cardano/Wallet/Byron/Compatibility.hs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ mainnetNetworkParameters = W.NetworkParameters
Quantity 4096
}
, desiredNumberOfStakePools = 0
, minimumUTxOvalue = W.Coin 0
}
}

Expand Down Expand Up @@ -446,6 +447,7 @@ protocolParametersFromPP pp = W.ProtocolParameters
, getTxMaxSize = fromMaxTxSize $ Update.ppMaxTxSize pp
}
, desiredNumberOfStakePools = 0
, minimumUTxOvalue = W.Coin 0
}

-- | Extract the protocol parameters relevant to the wallet out of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ spec = do
-- for Shelley desiredPoolNumber is node's nOpt protocol parameter
-- in integration test setup it is 3
let nOpt = 3
let minUtxoValue = Quantity 0
verify r
[ expectField (#decentralizationLevel) (`shouldBe` d)
, expectField (#desiredPoolNumber) (`shouldBe` nOpt)]
, expectField (#desiredPoolNumber) (`shouldBe` nOpt)
, expectField (#minimumUtxoValue) (`shouldBe` minUtxoValue)
]
48 changes: 27 additions & 21 deletions lib/core/src/Cardano/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,10 +1123,11 @@ feeOpts
:: TransactionLayer t k
-> Maybe DelegationAction
-> FeePolicy
-> W.Coin
-> FeeOptions
feeOpts tl action feePolicy = FeeOptions
feeOpts tl action feePolicy minUtxo = FeeOptions
{ estimateFee = minimumFee tl feePolicy action
, dustThreshold = minBound
, dustThreshold = minUtxo
, onDanglingChange = if allowUnbalancedTx tl then SaveMoney else PayAndBalance
}

Expand All @@ -1147,9 +1148,9 @@ selectCoinsForPayment
-> Quantity "lovelace" Word64
-> ExceptT (ErrSelectForPayment e) IO CoinSelection
selectCoinsForPayment ctx wid recipients withdrawal = do
(utxo, txp) <- withExceptT ErrSelectForPaymentNoSuchWallet $
(utxo, txp, minUtxo) <- withExceptT ErrSelectForPaymentNoSuchWallet $
selectCoinsSetup @ctx @s @k ctx wid
selectCoinsForPaymentFromUTxO @ctx @t @k @e ctx utxo txp recipients withdrawal
selectCoinsForPaymentFromUTxO @ctx @t @k @e ctx utxo txp minUtxo recipients withdrawal

-- | Retrieve wallet data which is needed for all types of coin selections.
selectCoinsSetup
Expand All @@ -1158,12 +1159,13 @@ selectCoinsSetup
)
=> ctx
-> WalletId
-> ExceptT ErrNoSuchWallet IO (W.UTxO, W.TxParameters)
-> ExceptT ErrNoSuchWallet IO (W.UTxO, W.TxParameters, W.Coin)
selectCoinsSetup ctx wid = do
(wal, _, pending) <- readWallet @ctx @s @k ctx wid
txp <- txParameters <$> readWalletProtocolParameters @ctx @s @k ctx wid
minUTxO <- minimumUTxOvalue <$> readWalletProtocolParameters @ctx @s @k ctx wid
let utxo = availableUTxO @s pending wal
return (utxo, txp)
return (utxo, txp, minUTxO)

selectCoinsForPaymentFromUTxO
:: forall ctx t k e.
Expand All @@ -1174,16 +1176,17 @@ selectCoinsForPaymentFromUTxO
=> ctx
-> W.UTxO
-> W.TxParameters
-> W.Coin
-> NonEmpty TxOut
-> Quantity "lovelace" Word64
-> ExceptT (ErrSelectForPayment e) IO CoinSelection
selectCoinsForPaymentFromUTxO ctx utxo txp recipients withdrawal = do
selectCoinsForPaymentFromUTxO ctx utxo txp minUtxo recipients withdrawal = do
lift . traceWith tr $ MsgPaymentCoinSelectionStart utxo txp recipients
(sel, utxo') <- withExceptT ErrSelectForPaymentCoinSelection $ do
let opts = coinSelOpts tl (txp ^. #getTxMaxSize)
CoinSelection.random opts recipients withdrawal utxo
lift . traceWith tr $ MsgPaymentCoinSelection sel
let feePolicy = feeOpts tl Nothing (txp ^. #getFeePolicy)
let feePolicy = feeOpts tl Nothing (txp ^. #getFeePolicy) minUtxo
withExceptT ErrSelectForPaymentFee $ do
balancedSel <- adjustForFee feePolicy utxo' sel
lift . traceWith tr $ MsgPaymentCoinSelectionAdjusted balancedSel
Expand All @@ -1205,9 +1208,9 @@ selectCoinsForDelegation
-> DelegationAction
-> ExceptT ErrSelectForDelegation IO CoinSelection
selectCoinsForDelegation ctx wid action = do
(utxo, txp) <- withExceptT ErrSelectForDelegationNoSuchWallet $
(utxo, txp, minUtxo) <- withExceptT ErrSelectForDelegationNoSuchWallet $
selectCoinsSetup @ctx @s @k ctx wid
selectCoinsForDelegationFromUTxO @_ @t @k ctx utxo txp action
selectCoinsForDelegationFromUTxO @_ @t @k ctx utxo txp minUtxo action

selectCoinsForDelegationFromUTxO
:: forall ctx t k.
Expand All @@ -1217,10 +1220,11 @@ selectCoinsForDelegationFromUTxO
=> ctx
-> W.UTxO
-> W.TxParameters
-> W.Coin
-> DelegationAction
-> ExceptT ErrSelectForDelegation IO CoinSelection
selectCoinsForDelegationFromUTxO ctx utxo txp action = do
let feePolicy = feeOpts tl (Just action) (txp ^. #getFeePolicy)
selectCoinsForDelegationFromUTxO ctx utxo txp minUtxo action = do
let feePolicy = feeOpts tl (Just action) (txp ^. #getFeePolicy) minUtxo
let sel = initDelegationSelection tl (txp ^. #getFeePolicy) action
withExceptT ErrSelectForDelegationFee $ do
balancedSel <- adjustForFee feePolicy utxo sel
Expand All @@ -1241,15 +1245,16 @@ estimateFeeForDelegation
-> WalletId
-> ExceptT ErrSelectForDelegation IO FeeEstimation
estimateFeeForDelegation ctx wid = db & \DBLayer{..} -> do
(utxo, txp) <- withExceptT ErrSelectForDelegationNoSuchWallet
(utxo, txp, minUtxo) <- withExceptT ErrSelectForDelegationNoSuchWallet
$ selectCoinsSetup @ctx @s @k ctx wid

isKeyReg <- mapExceptT atomically
$ withExceptT ErrSelectForDelegationNoSuchWallet
$ isStakeKeyRegistered (PrimaryKey wid)

let action = if isKeyReg then Join pid else RegisterKeyAndJoin pid
let selectCoins = selectCoinsForDelegationFromUTxO @_ @t @k ctx utxo txp action
let selectCoins =
selectCoinsForDelegationFromUTxO @_ @t @k ctx utxo txp minUtxo action
estimateFeeForCoinSelection $ Fee . feeBalance <$> selectCoins
where
db = ctx ^. dbLayer @s @k
Expand All @@ -1272,9 +1277,9 @@ selectCoinsForMigration
-- ^ The source wallet ID.
-> ExceptT ErrSelectForMigration IO [CoinSelection]
selectCoinsForMigration ctx wid = do
(utxo, txp) <- withExceptT ErrSelectForMigrationNoSuchWallet $
(utxo, txp, minUtxo) <- withExceptT ErrSelectForMigrationNoSuchWallet $
selectCoinsSetup @ctx @s @k ctx wid
selectCoinsForMigrationFromUTxO @ctx @t @k ctx utxo txp wid
selectCoinsForMigrationFromUTxO @ctx @t @k ctx utxo txp minUtxo wid

selectCoinsForMigrationFromUTxO
:: forall ctx t k.
Expand All @@ -1283,13 +1288,14 @@ selectCoinsForMigrationFromUTxO
=> ctx
-> W.UTxO
-> W.TxParameters
-> W.Coin
-> WalletId
-- ^ The source wallet ID.
-> ExceptT ErrSelectForMigration IO [CoinSelection]
selectCoinsForMigrationFromUTxO ctx utxo txp wid = do
selectCoinsForMigrationFromUTxO ctx utxo txp minUtxo wid = do
let feePolicy@(LinearFee (Quantity a) _ _) = txp ^. #getFeePolicy
let feeOptions = (feeOpts tl Nothing feePolicy)
{ dustThreshold = Coin $ ceiling a }
let minUtxo' = max (Coin $ ceiling a) minUtxo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

let feeOptions = feeOpts tl Nothing feePolicy minUtxo'
let selOptions = coinSelOpts tl (txp ^. #getTxMaxSize)
case depleteUTxO feeOptions (idealBatchSize selOptions) utxo of
cs | not (null cs) -> pure cs
Expand All @@ -1311,10 +1317,10 @@ estimateFeeForPayment
-> Quantity "lovelace" Word64
-> ExceptT (ErrSelectForPayment e) IO FeeEstimation
estimateFeeForPayment ctx wid recipients withdrawal = do
(utxo, txp) <- withExceptT ErrSelectForPaymentNoSuchWallet $
(utxo, txp, minUtxo) <- withExceptT ErrSelectForPaymentNoSuchWallet $
selectCoinsSetup @ctx @s @k ctx wid
let selectCoins =
selectCoinsForPaymentFromUTxO @ctx @t @k @e ctx utxo txp recipients withdrawal
selectCoinsForPaymentFromUTxO @ctx @t @k @e ctx utxo txp minUtxo recipients withdrawal
estimateFeeForCoinSelection $ (Fee . feeBalance <$> selectCoins)
`catchE` handleCannotCover utxo recipients

Expand Down
2 changes: 2 additions & 0 deletions lib/core/src/Cardano/Wallet/Api/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ data ApiNetworkParameters = ApiNetworkParameters
, activeSlotCoefficient :: !(Quantity "percent" Double)
, decentralizationLevel :: !(Quantity "percent" Percentage)
, desiredPoolNumber :: !Word16
, minimumUtxoValue :: !(Quantity "lovelace" Natural)
} deriving (Eq, Generic, Show)

toApiNetworkParameters :: NetworkParameters -> ApiNetworkParameters
Expand All @@ -520,6 +521,7 @@ toApiNetworkParameters (NetworkParameters gp pp) = ApiNetworkParameters
$ getActiveSlotCoefficient gp)
(Quantity $ unDecentralizationLevel $ view #decentralizationLevel pp)
(view #desiredNumberOfStakePools pp)
(Quantity $ fromIntegral $ getCoin $ view #minimumUTxOvalue pp)

newtype ApiTxId = ApiTxId
{ id :: ApiT (Hash "Tx")
Expand Down
81 changes: 45 additions & 36 deletions lib/core/src/Cardano/Wallet/DB/Sqlite.hs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ import Data.Proxy
( Proxy (..) )
import Data.Quantity
( Quantity (..) )
import Data.Text
( Text )
import Data.Text.Class
( ToText (..), fromText )
import Data.Typeable
Expand Down Expand Up @@ -330,6 +332,8 @@ migrateManually tr defaultFieldValues =

addDesiredPoolNumberIfMissing conn

addMinimumUTxOValueIfMissing conn

-- FIXME
-- Temporary migration to fix Daedalus flight wallets. This should
-- really be removed as soon as we have a fix for the cardano-sl:wallet
Expand Down Expand Up @@ -420,25 +424,9 @@ migrateManually tr defaultFieldValues =
-- it is missing.
--
addActiveSlotCoefficientIfMissing :: Sqlite.Connection -> IO ()
addActiveSlotCoefficientIfMissing conn = do
isFieldPresent conn activeSlotCoeff >>= \case
TableMissing ->
traceWith tr $ MsgManualMigrationNotNeeded activeSlotCoeff
ColumnMissing -> do
traceWith tr $ MsgManualMigrationNeeded activeSlotCoeff value
addColumn <- Sqlite.prepare conn $ T.unwords
[ "ALTER TABLE", tableName activeSlotCoeff
, "ADD COLUMN", fieldName activeSlotCoeff
, fieldType activeSlotCoeff, "NOT NULL", "DEFAULT", value
, ";"
]
_ <- Sqlite.step addColumn
Sqlite.finalize addColumn
ColumnPresent ->
traceWith tr $ MsgManualMigrationNotNeeded activeSlotCoeff

addActiveSlotCoefficientIfMissing conn =
addColumn conn (DBField CheckpointActiveSlotCoeff) value
where
activeSlotCoeff = DBField CheckpointActiveSlotCoeff
value = toText
$ W.unActiveSlotCoefficient
$ defaultActiveSlotCoefficient defaultFieldValues
Expand All @@ -448,25 +436,19 @@ migrateManually tr defaultFieldValues =
--
addDesiredPoolNumberIfMissing :: Sqlite.Connection -> IO ()
addDesiredPoolNumberIfMissing conn = do
isFieldPresent conn desiredPoolNumber >>= \case
TableMissing ->
traceWith tr $ MsgManualMigrationNotNeeded desiredPoolNumber
ColumnMissing -> do
traceWith tr $ MsgManualMigrationNeeded desiredPoolNumber value
addColumn <- Sqlite.prepare conn $ T.unwords
[ "ALTER TABLE", tableName desiredPoolNumber
, "ADD COLUMN", fieldName desiredPoolNumber
, fieldType desiredPoolNumber, "NOT NULL", "DEFAULT", value
, ";"
]
_ <- Sqlite.step addColumn
Sqlite.finalize addColumn
ColumnPresent ->
traceWith tr $ MsgManualMigrationNotNeeded desiredPoolNumber
addColumn conn (DBField ProtocolParametersDesiredNumberOfPools) value
where
desiredPoolNumber = DBField ProtocolParametersDesiredNumberOfPools
value = T.pack $ show $ defaultDesiredNumberOfPool defaultFieldValues

-- | Adds an 'minimum_utxo_value' column to the 'protocol_parameters'
-- table if it is missing.
--
addMinimumUTxOValueIfMissing :: Sqlite.Connection -> IO ()
addMinimumUTxOValueIfMissing conn = do
addColumn conn (DBField ProtocolParametersMinimumUtxoValue) value
where
value = T.pack $ show $ defaultMinimumUTxOValue defaultFieldValues

-- | This table became @protocol_parameters@.
removeOldTxParametersTable :: Sqlite.Connection -> IO ()
removeOldTxParametersTable conn = do
Expand All @@ -491,12 +473,37 @@ migrateManually tr defaultFieldValues =
| otherwise -> ColumnMissing
_ -> TableMissing

-- | A migration for adding a non-existing column to a table. Factor out as
-- it's a common use-case.
addColumn
:: Sqlite.Connection
-> DBField
-> Text
-> IO ()
addColumn conn field value = do
isFieldPresent conn field >>= \case
TableMissing ->
traceWith tr $ MsgManualMigrationNotNeeded field
ColumnMissing -> do
traceWith tr $ MsgManualMigrationNeeded field value
query <- Sqlite.prepare conn $ T.unwords
[ "ALTER TABLE", tableName field
, "ADD COLUMN", fieldName field
, fieldType field, "NOT NULL", "DEFAULT", value
, ";"
]
_ <- Sqlite.step query
Sqlite.finalize query
ColumnPresent ->
traceWith tr $ MsgManualMigrationNotNeeded field

-- | A set of default field values that can be consulted when performing a
-- database migration.
--
data DefaultFieldValues = DefaultFieldValues
{ defaultActiveSlotCoefficient :: W.ActiveSlotCoefficient
, defaultDesiredNumberOfPool :: Word16
, defaultMinimumUTxOValue :: W.Coin
}

-- | Sets up a connection to the SQLite database.
Expand Down Expand Up @@ -1061,22 +1068,24 @@ mkProtocolParametersEntity
-> W.ProtocolParameters
-> ProtocolParameters
mkProtocolParametersEntity wid pp =
ProtocolParameters wid fp (getQuantity mx) dl desiredPoolNum
ProtocolParameters wid fp (getQuantity mx) dl desiredPoolNum minUTxO
where
(W.ProtocolParameters
(W.DecentralizationLevel dl)
(W.TxParameters fp mx)
desiredPoolNum
minUTxO
) = pp

protocolParametersFromEntity
:: ProtocolParameters
-> W.ProtocolParameters
protocolParametersFromEntity (ProtocolParameters _ fp mx dl poolNum) =
protocolParametersFromEntity (ProtocolParameters _ fp mx dl poolNum minUTxO) =
W.ProtocolParameters
(W.DecentralizationLevel dl)
(W.TxParameters fp (Quantity mx))
poolNum
minUTxO

{-------------------------------------------------------------------------------
DB Queries
Expand Down
1 change: 1 addition & 0 deletions lib/core/src/Cardano/Wallet/DB/Sqlite/TH.hs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ ProtocolParameters
protocolParametersTxMaxSize Word16 sql=tx_max_size
protocolParametersDecentralizationLevel Percentage sql=decentralization_level
protocolParametersDesiredNumberOfPools Word16 sql=desired_pool_number
protocolParametersMinimumUtxoValue W.Coin sql=minimum_utxo_value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to need a migration for this one with a default value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cherry-picked one commit and also handled the migration in 487bb4f

Primary protocolParametersWalletId
Foreign Wallet fk_wallet_protocol_parameters protocolParametersWalletId ! ON DELETE CASCADE
deriving Show Generic
Expand Down
4 changes: 4 additions & 0 deletions lib/core/src/Cardano/Wallet/Primitive/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,9 @@ data ProtocolParameters = ProtocolParameters
:: Word16
-- ^ The current desired number of stakepools in the network.
-- Also known as k parameter.
, minimumUTxOvalue
:: Coin
-- ^ The minimu UTxO value.
} deriving (Eq, Generic, Show)

instance NFData ProtocolParameters
Expand All @@ -1408,6 +1411,7 @@ instance Buildable ProtocolParameters where
[ "Decentralization level: " <> build (pp ^. #decentralizationLevel)
, "Transaction parameters: " <> build (pp ^. #txParameters)
, "Desired number of pools: " <> build (pp ^. #desiredNumberOfStakePools)
, "Minimum UTxO value: " <> build (pp ^. #minimumUTxOvalue)
]

-- | Indicates the current level of decentralization in the network.
Expand Down
1 change: 1 addition & 0 deletions lib/core/test/bench/db/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ defaultFieldValues :: DefaultFieldValues
defaultFieldValues = DefaultFieldValues
{ defaultActiveSlotCoefficient = ActiveSlotCoefficient 1.0
, defaultDesiredNumberOfPool = 50
, defaultMinimumUTxOValue = Coin 0
-- NOTE value in the genesis when at the time this migration was needed.
}

Expand Down