Skip to content

Commit

Permalink
Use AddressState in Cardano.Wallet.Deposit.Pure
Browse files Browse the repository at this point in the history
  • Loading branch information
HeinrichApfelmus committed May 3, 2024
1 parent c26348b commit adf6f8c
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 51 deletions.
3 changes: 3 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ package cardano-wallet-integration
package cardano-wallet-test-utils
tests: True

package customer-deposit-wallet
tests: True

package std-gen-seed
tests: True

Expand Down
3 changes: 3 additions & 0 deletions lib/customer-deposit-wallet/customer-deposit-wallet.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ test-suite unit
main-is: test-suite-unit.hs
build-depends:
, base
, bytestring
, cardano-crypto
, cardano-wallet:cardano-wallet
, cardano-wallet-primitive
, cardano-wallet-test-utils
Expand All @@ -109,6 +111,7 @@ test-suite scenario
-pgmL markdown-unlit
build-depends:
, base
, bytestring
, cardano-crypto
, cardano-wallet-test-utils
, containers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ deriving via ViaText Address instance ToJSON (ApiT Address)

-- Customer
instance FromHttpApiData (ApiT Customer) where
parseUrlPiece = fmap ApiT . fromText'
parseUrlPiece = fmap (ApiT . toEnum) . fromText'

instance FromJSON (ApiT Customer) where
parseJSON = fmap ApiT . parseJSON
parseJSON = fmap (ApiT . toEnum) . parseJSON

instance ToJSON (ApiT Customer) where
toJSON = toJSON . unApiT
toJSON = toJSON . fromEnum . unApiT

-- | 'fromText' but with a simpler error type.
fromText' :: FromText a => Text -> Either Text a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ readWalletState WalletInstance{env,walletState} =
-- | Initialize a new wallet in the given environment.
withWalletInit
:: XPub
-> Integer
-> Int
-> WalletEnv IO
-> (WalletInstance -> IO a)
-> IO a
Expand Down
64 changes: 27 additions & 37 deletions lib/customer-deposit-wallet/src/Cardano/Wallet/Deposit/Pure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ module Cardano.Wallet.Deposit.Pure

, addTxSubmission
, listTxsInSubmission

-- * Internal
, fromGenesisUTxO
) where

import Prelude
Expand All @@ -49,6 +46,9 @@ import Cardano.Wallet.Deposit.Pure.UTxOHistory
import Cardano.Wallet.Deposit.Read
( Address
)
import Data.Bifunctor
( second
)
import Data.Foldable
( foldl'
)
Expand All @@ -58,40 +58,32 @@ import Data.List.NonEmpty
import Data.Map
( Map
)
import Data.Maybe
( isJust
)
import Data.Set
( Set
)
import Numeric.Natural
( Natural
)

import qualified Cardano.Wallet.Deposit.Pure.Address as Address
import qualified Cardano.Wallet.Deposit.Pure.Balance as Balance
import qualified Cardano.Wallet.Deposit.Pure.Submissions as Sbm
import qualified Cardano.Wallet.Deposit.Pure.UTxO as UTxO
import qualified Cardano.Wallet.Deposit.Pure.UTxOHistory as UTxOHistory
import qualified Cardano.Wallet.Deposit.Read as Read
import qualified Cardano.Wallet.Deposit.Write as Write
import qualified Data.Delta as Delta
import qualified Data.Map.Strict as Map

{-----------------------------------------------------------------------------
Types
------------------------------------------------------------------------------}
type Customer = Natural
type Customer = Address.Customer

data WalletState = WalletState
{ customers :: !(Map Customer Address)
, changeAddress :: !Address
{ addresses :: !Address.AddressState
, utxoHistory :: !UTxOHistory.UTxOHistory
-- , txHistory :: [Read.Tx]
, submissions :: Sbm.TxSubmissions
-- , credentials :: Maybe (HashedCredentials (KeyOf s))
-- , info :: !WalletInfo
}
deriving (Eq, Show)

type DeltaWalletState = Delta.Replace WalletState

Expand All @@ -101,47 +93,47 @@ type DeltaWalletState = Delta.Replace WalletState
------------------------------------------------------------------------------}

listCustomers :: WalletState -> [(Customer, Address)]
listCustomers = Map.toList . customers
listCustomers =
map (second Read.fromRawAddress)
. Address.listCustomers . addresses

createAddress :: Customer -> WalletState -> (Address, WalletState)
createAddress customer w1 = (address, w2)
createAddress customer w0 =
(Read.fromRawAddress address, w0{addresses = s1})
where
address = deriveAddress w1 customer
w2 = w1{customers = Map.insert customer address (customers w1)}
(address, s1) = Address.createAddress customer (addresses w0)

-- depend on the private key only, not on the entire wallet state
deriveAddress :: WalletState -> (Customer -> Address)
deriveAddress _ = Read.mockAddress

-- FIXME: More performant with a double index.
knownCustomer :: Customer -> WalletState -> Bool
knownCustomer c = (c `Map.member`) . customers
knownCustomer c = (c `elem`) . map fst . listCustomers

knownCustomerAddress :: Address -> WalletState -> Bool
knownCustomerAddress address = isJust . isCustomerAddress address
knownCustomerAddress address =
Address.knownCustomerAddress (Read.toRawAddress address) . addresses

isCustomerAddress :: Address -> WalletState -> Maybe Customer
isCustomerAddress address w =
case filter ((== address) . snd) (Map.toList $ customers w) of
[(customer,_address)] -> Just customer
_ -> Nothing
isCustomerAddress :: Address -> WalletState -> Bool
isCustomerAddress address =
flip Address.isCustomerAddress (Read.toRawAddress address) . addresses

{-----------------------------------------------------------------------------
Operations
Reading from the blockchain
------------------------------------------------------------------------------}

fromXPubAndGenesis :: XPub -> Integer -> Read.GenesisData -> WalletState
fromXPubAndGenesis _xpub _knownCustomerCount _ = fromGenesisUTxO mempty
-- FIXME: This is a mock implementation

fromGenesisUTxO :: Read.UTxO -> WalletState
fromGenesisUTxO utxo =
fromXPubAndGenesis :: XPub -> Int -> Read.GenesisData -> WalletState
fromXPubAndGenesis xpub knownCustomerCount _ =
WalletState
{ customers = Map.empty
, changeAddress = Read.dummyAddress
, utxoHistory = UTxOHistory.empty utxo
{ addresses =
Address.fromXPubAndCount xpub (toEnum knownCustomerCount)
, utxoHistory = UTxOHistory.empty initialUTxO
, submissions = Sbm.empty
}
where
initialUTxO = mempty

getWalletTip :: WalletState -> Read.ChainPoint
getWalletTip = error "getWalletTip"
Expand All @@ -157,9 +149,7 @@ rollForwardOne block w =
}
where
isOurs :: Address -> Bool
isOurs addr =
( addr == changeAddress w ) || knownCustomerAddress addr w
-- FIXME: Consider payment part only, ignore staking part.
isOurs = Address.isOurs (addresses w) . Read.toRawAddress

rollForwardUTxO
:: (Address -> Bool) -> Read.Block -> UTxOHistory -> UTxOHistory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ module Cardano.Wallet.Deposit.Read

, Addr
, Address
, fromRawAddress
, toRawAddress
, mockAddress

, Ix
Expand Down Expand Up @@ -86,6 +88,12 @@ type Addr = W.Address
-- Byron addresses are represented by @Addr_bootstrap@.
type Address = Addr

fromRawAddress :: BS.ByteString -> Address
fromRawAddress = W.Address

toRawAddress :: Address -> BS.ByteString
toRawAddress (W.Address a) = a

mockAddress :: Show a => a -> Address
mockAddress = W.Address . B8.pack . show

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Prelude

import Cardano.Crypto.Wallet
( XPub
, generate
, toXPub
)
import Test.Hspec
( SpecWith
Expand All @@ -32,6 +34,7 @@ import Test.Scenario.Blockchain
)

import qualified Cardano.Wallet.Deposit.IO as Wallet
import qualified Data.ByteString.Char8 as B8
import qualified Test.Scenario.Wallet.Deposit.Exchanges as Exchanges

main :: IO ()
Expand Down Expand Up @@ -63,7 +66,9 @@ scenarios = do
testBalance env

xpub :: XPub
xpub = error "todo: xpub"
xpub =
toXPub
$ generate (B8.pack "random seed for a testing xpub lala") B8.empty

testBalance
:: ScenarioEnv -> Wallet.WalletInstance -> IO ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ module Cardano.Wallet.Deposit.PureSpec

import Prelude

import Cardano.Crypto.Wallet
( XPub
, generate
, toXPub
)
import Cardano.Wallet.Primitive.Types.Tx.TxSeq
( toTxList
)
Expand All @@ -25,14 +30,17 @@ import Test.Hspec
import Test.QuickCheck
( Gen
, Property
, checkCoverage
, cover
, elements
, forAll
, property
, suchThat
)

import qualified Cardano.Wallet.Deposit.Pure as Wallet
import qualified Cardano.Wallet.Deposit.Read as Read
import qualified Data.ByteString.Char8 as B8

spec :: Spec
spec = do
Expand All @@ -46,14 +54,29 @@ spec = do
prop_rollForwardOne_UTxO
:: Property
prop_rollForwardOne_UTxO =
forAll genBlock $ \block ->
checkCoverage
$ forAll (genBlock genAddress) $ \block ->
-- The wallet has a nonzero balance most of the time
-- FIXME: Should have all the time?
cover 50 (hasFunds $ Wallet.rollForwardOne block w0)
cover 50 (hasFunds $ Wallet.rollForwardOne block w1)
"has balance" (property True)
where
w0 = Wallet.fromGenesisUTxO mempty
hasFunds w1 = mempty /= Wallet.availableBalance w1
w0 = Wallet.fromXPubAndGenesis xpub 0 (error "no genesis data")
hasFunds w = mempty /= Wallet.availableBalance w

(addr1, w1) = Wallet.createAddress 1 w0
genAddress :: Gen Read.Address
genAddress = elements
[ Read.fromRawAddress $ B8.pack "this is not a real address"
, Read.fromRawAddress $ B8.pack "also not a real address"
, Read.fromRawAddress $ B8.pack "this is a mock address"
, addr1
]

xpub :: XPub
xpub =
toXPub
$ generate (B8.pack "random seed for a testing xpub lala") B8.empty

hasOutputs :: Read.Tx -> Bool
hasOutputs tx =
Expand All @@ -64,8 +87,8 @@ hasOutputs tx =
haveSomeOutputs :: Read.Block -> Bool
haveSomeOutputs = any hasOutputs . Read.transactions

genBlock :: Gen Read.Block
genBlock =
genBlock :: Gen Read.Address -> Gen Read.Block
genBlock genAddress =
(mkBlock <$> genTxs) `suchThat` haveSomeOutputs
where
genTxs = toTxList . getTxSeq <$> genTxSeq genUTxO genAddress
Expand All @@ -74,6 +97,3 @@ genBlock =
{ Read.blockHeader = Read.dummyBHeader
, Read.transactions = transactions
}

genAddress :: Gen Read.Address
genAddress = pure Read.dummyAddress

0 comments on commit adf6f8c

Please sign in to comment.