Skip to content

Commit

Permalink
Use a null address and minimal coin value within `performSelectionEmp…
Browse files Browse the repository at this point in the history
…ty`.

Now that `performSelectionNonEmpty` no longer validates the minimum ada
quantities of user-specified outputs (a responsibility that has been
moved to the top-level coin selection module), we are free to choose any
`Address` (even if invalid) and any non-zero `Coin` value for the dummy
output used by `performSelectionEmpty`.

In order to minimize any overestimation in cost resulting from the use
of a dummy output, we choose the shortest possible `Address` (which is a
null-length address) and the smallest possible non-zero `Coin` value.
  • Loading branch information
jonathanknowles committed Aug 1, 2022
1 parent 0a61058 commit 6c270a5
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 31 deletions.
6 changes: 2 additions & 4 deletions lib/core/src/Cardano/Wallet/CoinSelection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ import Cardano.Wallet.Primitive.Collateral
( asCollateral )
import Cardano.Wallet.Primitive.Types.Address
( Address (..) )
import Cardano.Wallet.Primitive.Types.Address.Constants
( minLengthAddress )
import Cardano.Wallet.Primitive.Types.Coin
( Coin (..) )
import Cardano.Wallet.Primitive.Types.TokenBundle
Expand Down Expand Up @@ -261,8 +259,8 @@ toInternalSelectionConstraints SelectionConstraints {..} =
txOutMaxCoin
, maximumOutputTokenQuantity =
txOutMaxTokenQuantity
, minimumLengthChangeAddress =
minLengthAddress
, nullAddress =
Address ""
, ..
}

Expand Down
6 changes: 3 additions & 3 deletions lib/core/src/Cardano/Wallet/CoinSelection/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ data SelectionConstraints ctx = SelectionConstraints
-- token bundle of an output.
, maximumLengthChangeAddress
:: Address ctx
, minimumLengthChangeAddress
, nullAddress
:: Address ctx
}
deriving Generic
Expand Down Expand Up @@ -421,8 +421,8 @@ toBalanceConstraintsParams (constraints, params) =
view #maximumOutputTokenQuantity constraints
, maximumLengthChangeAddress =
view #maximumLengthChangeAddress constraints
, minimumLengthChangeAddress =
view #minimumLengthChangeAddress constraints
, nullAddress =
view #nullAddress constraints
}
where
adjustComputeMinimumCost
Expand Down
47 changes: 26 additions & 21 deletions lib/core/src/Cardano/Wallet/CoinSelection/Internal/Balance.hs
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,6 @@ data SelectionConstraints ctx = SelectionConstraints
-- select, given a current set of outputs.
, maximumLengthChangeAddress
:: Address ctx
, minimumLengthChangeAddress
:: Address ctx
, maximumOutputAdaQuantity
:: Coin
-- ^ Specifies the largest ada quantity that can appear in the token
Expand All @@ -239,6 +237,8 @@ data SelectionConstraints ctx = SelectionConstraints
:: TokenQuantity
-- ^ Specifies the largest non-ada quantity that can appear in the
-- token bundle of an output.
, nullAddress
:: Address ctx
}
deriving Generic

Expand Down Expand Up @@ -804,7 +804,7 @@ performSelectionEmpty performSelectionFn constraints params =
-> SelectionParamsOf NonEmpty ctx
transformParams p@SelectionParams {..} = p
{ extraCoinSource =
transform (`Coin.add` minCoin) (const id) extraCoinSource
transform (`Coin.add` dummyCoin) (const id) extraCoinSource
, outputsToCover =
transform (const (dummyOutput :| [])) (const . id) outputsToCover
}
Expand All @@ -814,37 +814,42 @@ performSelectionEmpty performSelectionFn constraints params =
-> SelectionResultOf [] ctx
transformResult r@SelectionResult {..} = r
{ extraCoinSource =
transform (`Coin.difference` minCoin) (const id) extraCoinSource
transform (`Coin.difference` dummyCoin) (const id) extraCoinSource
, outputsCovered =
transform (const []) (const . F.toList) outputsCovered
}

transform :: a -> (NonEmpty (Address ctx, TokenBundle) -> a) -> a
transform x y = maybe x y $ NE.nonEmpty $ view #outputsToCover params

dummyAddress :: Address ctx
dummyAddress = minimumLengthChangeAddress constraints

-- A dummy output that is added before calling 'performSelectionNonEmpty'
-- and removed immediately after selection is complete.
--
dummyOutput :: (Address ctx, TokenBundle)
dummyOutput = (dummyAddress, TokenBundle.fromCoin minCoin)
dummyOutput = (dummyAddress, TokenBundle.fromCoin dummyCoin)

-- The 'performSelectionNonEmpty' function imposes a precondition that all
-- outputs must have at least the minimum ada quantity. Therefore, the
-- dummy output must also satisfy this condition.
-- A dummy 'Address' value for the dummy output.
--
-- However, we must also ensure that the value is non-zero, since:
-- We can use a null address here, as 'performSelectionNonEmpty' does not
-- verify the minimum ada quantities of user-specified outputs, and hence
-- we do not need to provide a valid address.
--
-- 1. Under some cost models, the 'computeMinimumAdaQuantity' function
-- has a constant value of zero.
-- Using a null address allows us to minimize any overestimation in cost
-- resulting from the use of a dummy output.
--
-- 2. The change generation algorithm requires that the total ada balance
-- of all outputs is non-zero.
dummyAddress = nullAddress constraints

-- A dummy 'Coin' value for the dummy output.
--
minCoin :: Coin
minCoin = max
(Coin 1)
(view #computeMinimumAdaQuantity constraints dummyAddress TokenMap.empty
)
-- This value is chosen to be as small as possible in order to minimize
-- any overestimation in cost resulting from the use of a dummy output.
--
-- However, we cannot choose a value of zero, since the change generation
-- algorithm requires that the total ada balance of all outputs is
-- non-zero, so instead we specify the smallest possible non-zero value.
--
dummyCoin :: Coin
dummyCoin = Coin 1

performSelectionNonEmpty
:: forall m ctx. (HasCallStack, MonadRandom m, SelectionContext ctx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1842,7 +1842,7 @@ mkBoundaryTestExpectation (BoundaryTestData params expectedResult) = do
, maximumOutputAdaQuantity = testMaximumOutputAdaQuantity
, maximumOutputTokenQuantity = testMaximumOutputTokenQuantity
, maximumLengthChangeAddress = TestAddress 0x0
, minimumLengthChangeAddress = TestAddress 0x0
, nullAddress = TestAddress 0x0
}

encodeBoundaryTestCriteria
Expand Down Expand Up @@ -2477,7 +2477,7 @@ unMockSelectionConstraints m = SelectionConstraints
testMaximumOutputTokenQuantity
, maximumLengthChangeAddress =
TestAddress 0x0
, minimumLengthChangeAddress =
, nullAddress =
TestAddress 0x0
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ unMockSelectionConstraints m = SelectionConstraints
view #maximumOutputTokenQuantity m
, maximumLengthChangeAddress =
TestAddress 0x0
, minimumLengthChangeAddress =
, nullAddress =
TestAddress 0x0
}

Expand Down

0 comments on commit 6c270a5

Please sign in to comment.