Skip to content

Commit 62d79d2

Browse files
authored
Add restoration point option on post account wallet end point (#4984)
### Changes - Add restoration point option in post account wallet end point ### Issues fix #4967
2 parents 80f3140 + 7fa49db commit 62d79d2

File tree

8 files changed

+172
-29
lines changed

8 files changed

+172
-29
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ cabal.project.diff
3939
### Direnv ###
4040
.envrc-local
4141
.envrc-override
42-
.direnv/flake-profile*
42+
.direnv
4343

4444
### auto-generated faulty JSON golden tests ###
4545
*.faulty.json

lib/api/src/Cardano/Wallet/Api/Http/Shelley/Server.hs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,8 @@ import Data.Generics.Internal.VL.Lens
751751
import Data.Generics.Labels
752752
()
753753
import Data.Generics.Product
754-
( typed
754+
( HasField'
755+
, typed
755756
)
756757
import Data.IntCast
757758
( intCastMaybe
@@ -955,6 +956,24 @@ postWallet ctx generateKey liftKey (WalletOrAccountPostData body) = case body of
955956

956957
in postAccountWallet ctx mkShelleyWallet liftKey action body'
957958

959+
computeRestorationPoint
960+
:: forall ctx s body
961+
. ( ctx ~ ApiLayer s
962+
, HasField' "restorationMode" body (Maybe (ApiT RestorationMode))
963+
)
964+
=> ctx
965+
-> NetworkParameters
966+
-> body
967+
-> Handler RestorationPoint
968+
computeRestorationPoint ctx networkParams body =
969+
liftHandler
970+
$ withExceptT ErrCreateWalletRestorationFromABlockFailed
971+
$ ExceptT
972+
$ getRestorationPoint
973+
(genesisParameters networkParams)
974+
(maybe RestoreFromGenesis getApiT $ body ^. #restorationMode)
975+
(ctx ^. networkLayer)
976+
958977
postShelleyWallet
959978
:: forall ctx s k n.
960979
( s ~ SeqState n k
@@ -975,12 +994,7 @@ postShelleyWallet ctx generateKey body = do
975994
let state = mkSeqStateFromRootXPrv
976995
(keyFlavorFromState @s) (RootCredentials rootXPrv pwdP)
977996
purposeCIP1852 g changeAddrMode
978-
restorationPoint <- liftHandler
979-
$ withExceptT ErrCreateWalletRestorationFromABlockFailed
980-
$ ExceptT $ getRestorationPoint
981-
(genesisParameters networkParams)
982-
(maybe RestoreFromGenesis getApiT $ restorationMode body)
983-
(ctx ^. networkLayer)
997+
restorationPoint <- computeRestorationPoint ctx networkParams body
984998
let initialState = InitialState state genesisBlock restorationPoint
985999
void $ liftHandler $ createWalletWorker @_ @s ctx wid
9861000
(W.createWallet @s networkParams wid wName initialState)
@@ -1025,9 +1039,10 @@ postAccountWallet
10251039
-> AccountPostData
10261040
-> Handler w
10271041
postAccountWallet ctx mkWallet liftKey coworker body = do
1042+
restorationPoint <- computeRestorationPoint ctx networkParams body
10281043
let state = mkSeqStateFromAccountXPub
10291044
(liftKey accXPub) Nothing purposeCIP1852 g IncreasingChangeAddresses
1030-
initialState = InitialState state genesisBlock RestorationPointAtGenesis
1045+
initialState = InitialState state genesisBlock restorationPoint
10311046
void $ liftHandler $ createWalletWorker @_ @s ctx wid
10321047
(W.createWallet @s networkParams wid wName initialState)
10331048
coworker

lib/api/src/Cardano/Wallet/Api/Types.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,7 @@ data AccountPostData = AccountPostData
11341134
{ name :: !(ApiT WalletName)
11351135
, accountPublicKey :: !ApiAccountPublicKey
11361136
, addressPoolGap :: !(Maybe (ApiT AddressPoolGap))
1137+
, restorationMode :: Maybe ApiRestorationMode
11371138
}
11381139
deriving (FromJSON, ToJSON) via DefaultRecord AccountPostData
11391140
deriving (Eq, Generic, Show)

lib/exe/lib/Cardano/Wallet/Application/CLI.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ cmdWalletCreateFromPublicKey mkClient =
751751
(ApiT wName)
752752
wAccPubKey
753753
(Just $ ApiT wGap)
754+
Nothing
754755

755756
-- | Arguments for 'wallet get' command
756757
data WalletGetArgs = WalletGetArgs

lib/integration/framework/Test/Integration/Framework/DSL/Wallet.hs

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{-# LANGUAGE DataKinds #-}
22
{-# LANGUAGE DuplicateRecordFields #-}
3+
{-# LANGUAGE FlexibleContexts #-}
34
{-# LANGUAGE OverloadedLabels #-}
45
{-# LANGUAGE PatternSynonyms #-}
56
{-# LANGUAGE ScopedTypeVariables #-}
67
{-# LANGUAGE TupleSections #-}
8+
{-# LANGUAGE TypeApplications #-}
79

810
module Test.Integration.Framework.DSL.Wallet
911
( createARandomWalletWithMnemonics
@@ -17,18 +19,27 @@ module Test.Integration.Framework.DSL.Wallet
1719
, named
1820
, fundWallet
1921
, withApiWallet
22+
, xPubOfMnemonics
23+
, createWalletFromXPub
24+
, withRestorationMode
2025
) where
2126

2227
import Prelude
2328

29+
import Cardano.Address.Derivation
30+
( XPub
31+
, toXPub
32+
)
2433
import Cardano.Mnemonic
2534
( SomeMnemonic
2635
)
2736
import Cardano.Wallet.Api.Clients.Testnet.Id
2837
( Testnet42
2938
)
3039
import Cardano.Wallet.Api.Types
31-
( AddressAmount (..)
40+
( AccountPostData (..)
41+
, AddressAmount (..)
42+
, ApiAccountPublicKey (..)
3243
, ApiMnemonicT (..)
3344
, ApiT (..)
3445
, ApiTxId (..)
@@ -46,11 +57,15 @@ import Cardano.Wallet.Api.Types.WalletAssets
4657
import Cardano.Wallet.Faucet
4758
( Faucet (nextShelleyMnemonic)
4859
)
60+
import Cardano.Wallet.Network.RestorationMode
61+
( RestorationMode
62+
)
4963
import Cardano.Wallet.Primitive.SyncProgress
5064
( SyncProgress (..)
5165
)
5266
import Cardano.Wallet.Primitive.Types
5367
( WalletId
68+
, WalletName
5469
)
5570
import Cardano.Wallet.Primitive.Types.Tx.TxMeta
5671
( TxStatus (InLedger)
@@ -72,6 +87,9 @@ import Data.Generics.Internal.VL
7287
( (.~)
7388
, (^.)
7489
)
90+
import Data.Generics.Product
91+
( HasField
92+
)
7593
import Data.Text
7694
( Text
7795
)
@@ -96,16 +114,36 @@ import Test.Integration.Framework.DSL.TestM
96114
, request
97115
)
98116

117+
import qualified Cardano.Address.Style.Shelley as Address
99118
import qualified Cardano.Faucet.Mnemonics as Mnemonics
100119
import qualified Cardano.Wallet.Api.Clients.Testnet.Shelley as C
101120

102121
type AWallet = ApiT WalletId
103122

104123
type Patch a = a -> a
105124

125+
createWalletFromXPub
126+
:: XPub
127+
-> Patch AccountPostData
128+
-> TestM (Either ClientError AWallet)
129+
createWalletFromXPub xpub refine = do
130+
apiWallet' <-
131+
request
132+
$ C.postWallet
133+
$ WalletOrAccountPostData
134+
$ Right
135+
$ refine
136+
$ AccountPostData
137+
{ name = ApiT $ unsafeFromText "Wallet from mnemonic"
138+
, accountPublicKey = ApiAccountPublicKey $ ApiT xpub
139+
, addressPoolGap = Nothing
140+
, restorationMode = Nothing
141+
}
142+
pure $ fmap (view #id) apiWallet'
143+
106144
createWalletFromMnemonics
107145
:: SomeMnemonic
108-
-> (WalletPostData -> WalletPostData)
146+
-> Patch WalletPostData
109147
-> TestM (Either ClientError AWallet)
110148
createWalletFromMnemonics m15 refine = do
111149
apiWallet' <-
@@ -125,9 +163,16 @@ createWalletFromMnemonics m15 refine = do
125163
}
126164
pure $ fmap (view #id) apiWallet'
127165

128-
createARandomWallet :: Patch WalletPostData -> TestM (Either ClientError AWallet)
166+
createARandomWallet
167+
:: Patch WalletPostData -> TestM (Either ClientError AWallet)
129168
createARandomWallet refine = fmap fst <$> createARandomWalletWithMnemonics refine
130169

170+
xPubOfMnemonics :: SomeMnemonic -> XPub
171+
xPubOfMnemonics mnemonic =
172+
let rootKey = Address.genMasterKeyFromMnemonic mnemonic mempty
173+
accKey = Address.deriveAccountPrivateKey rootKey minBound
174+
in toXPub $ Address.getKey accKey
175+
131176
createARandomWalletWithMnemonics
132177
:: Patch WalletPostData
133178
-- ^ Refine the wallet data
@@ -155,14 +200,24 @@ statusIs :: SyncProgress -> Over ApiWallet ()
155200
statusIs expected = check
156201
$ \w -> w ^. #state . #getApiT `shouldBe` expected
157202

158-
named :: Text -> Patch WalletPostData
159-
named name' = #name .~ ApiT (unsafeFromText name')
203+
named
204+
:: HasField "name" a a b (ApiT WalletName)
205+
=> Text
206+
-> Patch a
207+
named name' = #name .~ ApiT (unsafeFromText @WalletName name')
208+
209+
withRestorationMode
210+
:: HasField "restorationMode" a a b (Maybe (ApiT RestorationMode))
211+
=> RestorationMode
212+
-> Patch a
213+
withRestorationMode rm = #restorationMode .~ Just (ApiT rm)
160214

161215
aFaucetWallet :: TestM AWallet
162216
aFaucetWallet = do
163217
faucet <- asks _faucet
164218
faucetMnemonic <- liftIO $ nextShelleyMnemonic faucet
165-
Partial faucetWalletId <- createWalletFromMnemonics faucetMnemonic $ named "Faucet wallet"
219+
Partial faucetWalletId <-
220+
createWalletFromMnemonics faucetMnemonic $ named "Faucet wallet"
166221
over faucetWalletId waitUntilStateIsReady
167222
pure faucetWalletId
168223

lib/integration/scenarios/Test/Integration/Scenario/API/Shelley/Restoration.hs

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import Prelude
1414

1515
import Cardano.Wallet.Api.Types
1616
( ApiT (..)
17-
, WalletPostData (..)
1817
)
1918
import Cardano.Wallet.Api.Types.BlockHeader
2019
( ApiBlockHeader (..)
@@ -28,6 +27,9 @@ import Cardano.Wallet.Primitive.Types.Hash
2827
import Cardano.Wallet.Unsafe
2928
( unsafeFromText
3029
)
30+
import Data.Generics.Product
31+
( HasField
32+
)
3133
import Data.Quantity
3234
( Quantity (..)
3335
)
@@ -58,11 +60,14 @@ import Test.Integration.Framework.DSL.Wallet
5860
, createARandomWallet
5961
, createARandomWalletWithMnemonics
6062
, createWalletFromMnemonics
63+
, createWalletFromXPub
6164
, deleteWallet
6265
, fundWallet
6366
, named
6467
, waitUntilStateIsReady
6568
, withApiWallet
69+
, withRestorationMode
70+
, xPubOfMnemonics
6671
)
6772

6873
import qualified Cardano.Wallet.Api.Clients.Network as C
@@ -71,7 +76,8 @@ import qualified Cardano.Wallet.Read as Read
7176
spec :: SpecWith Context
7277
spec = describe "restoration of wallets" $ do
7378
itM "WALLET_RESTORE_0.1 create a wallet restoring from tip" $ do
74-
Partial w <- createARandomWallet $ named "Wallet from tip" . restoringFromTip
79+
Partial w <-
80+
createARandomWallet $ named "Wallet from tip" . restoringFromTip
7581
over w $ do
7682
waitUntilStateIsReady
7783
withApiWallet $ balanceIs 0
@@ -182,7 +188,9 @@ spec = describe "restoration of wallets" $ do
182188
ApiBlockHeader
183189
{ slotNo = Quantity 0
184190
, blockHeight = Quantity 0
185-
, headerHash = unsafeFromText "39d89a1e837e968ba35370be47cdfcbfd193cd992fdeed557b77c49b77ee59cf"
191+
, headerHash =
192+
unsafeFromText
193+
"39d89a1e837e968ba35370be47cdfcbfd193cd992fdeed557b77c49b77ee59cf"
186194
}
187195
w <- createARandomWallet (restoringFromCheckpoint cp)
188196
clientError w $ do
@@ -193,21 +201,83 @@ spec = describe "restoration of wallets" $ do
193201
\The block at slot number 0 \
194202
\and hash 39d89a1e837e968ba35370be47cdfcbfd193cd992fdeed557b77c49b77ee59cf \
195203
\does not exist."
204+
itM
205+
"WALLET_RESTORE_0.9 create an account wallet from the tip \
206+
\ignores past transactions"
207+
$ do
208+
Partial (genesisClone, mnemonics) <-
209+
createARandomWalletWithMnemonics
210+
$ named "Account from genesis" . restoringFromTip
211+
let xpub = xPubOfMnemonics mnemonics
212+
over genesisClone $ do
213+
waitUntilStateIsReady
214+
fundWallet 42_000_000
215+
withApiWallet $ balanceIs 42_000_000
216+
deleteWallet
217+
Partial tipClone <-
218+
createWalletFromXPub xpub
219+
$ named "Account from tip" . restoringFromTip
220+
over tipClone $ do
221+
waitUntilStateIsReady
222+
withApiWallet $ balanceIs 0
223+
itM
224+
"WALLET_RESTORE_0.10 create an account wallet from the genesis \
225+
\capture the past transactions"
226+
$ do
227+
Partial (genesisClone, mnemonics) <-
228+
createARandomWalletWithMnemonics
229+
$ named "Account from genesis" . restoringFromTip
230+
let xpub = xPubOfMnemonics mnemonics
231+
over genesisClone $ do
232+
waitUntilStateIsReady
233+
fundWallet 42_000_000
234+
withApiWallet $ balanceIs 42_000_000
235+
deleteWallet
236+
Partial tipClone <-
237+
createWalletFromXPub xpub
238+
$ named "Account from genesis second take" . restoringFromGenesis
239+
over tipClone $ do
240+
waitUntilStateIsReady
241+
withApiWallet $ balanceIs 42_000_000
242+
itM
243+
"WALLET_RESTORE_0.11 create an account wallet from checkpoint \
244+
\capture the past transactions"
245+
$ do
246+
Partial (genesisClone, mnemonics) <-
247+
createARandomWalletWithMnemonics
248+
$ named "Account from genesis" . restoringFromTip
249+
let xpub = xPubOfMnemonics mnemonics
250+
over genesisClone $ do
251+
waitUntilStateIsReady
252+
Partial cp <- request C.blocksLatestHeader
253+
waitSomeEpochs 2
254+
over genesisClone $ do
255+
fundWallet 42_000_000
256+
withApiWallet $ balanceIs 42_000_000
257+
deleteWallet
258+
Partial tipClone <-
259+
createWalletFromXPub xpub
260+
$ named "Account from a block" . restoringFromCheckpoint cp
261+
over tipClone $ do
262+
waitUntilStateIsReady
263+
withApiWallet $ balanceIs 42_000_000
196264

197-
setRestorationMode :: RestorationMode -> Patch WalletPostData
198-
setRestorationMode rm wd = wd{restorationMode = Just $ ApiT rm}
199-
200-
restoringFromTip :: Patch WalletPostData
201-
restoringFromTip = setRestorationMode RestoreFromTip
265+
restoringFromTip
266+
:: HasField "restorationMode" a a b (Maybe (ApiT RestorationMode))
267+
=> Patch a
268+
restoringFromTip = withRestorationMode RestoreFromTip
202269

203-
restoringFromGenesis :: Patch WalletPostData
204-
restoringFromGenesis = setRestorationMode RestoreFromGenesis
270+
restoringFromGenesis
271+
:: HasField "restorationMode" a a b (Maybe (ApiT RestorationMode))
272+
=> Patch a
273+
restoringFromGenesis = withRestorationMode RestoreFromGenesis
205274

206275
restoringFromCheckpoint
207-
:: ApiBlockHeader
208-
-> Patch WalletPostData
276+
:: HasField "restorationMode" a a b (Maybe (ApiT RestorationMode))
277+
=> ApiBlockHeader
278+
-> Patch a
209279
restoringFromCheckpoint cp =
210-
setRestorationMode
280+
withRestorationMode
211281
$ RestoreFromBlock
212282
(Read.SlotNo $ fromIntegral $ getQuantity $ slotNo cp)
213283
(toRawHeaderHash $ headerHash cp)

lib/unit/test/unit/Cardano/Wallet/Api/TypesSpec.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1584,7 +1584,7 @@ instance Arbitrary AccountPostData where
15841584
arbitrary = do
15851585
wName <- ApiT <$> arbitrary
15861586
accXPub <- arbitrary
1587-
pure $ AccountPostData wName accXPub Nothing
1587+
pure $ AccountPostData wName accXPub Nothing Nothing
15881588

15891589
instance Arbitrary WalletPostData where
15901590
arbitrary = genericArbitrary

0 commit comments

Comments
 (0)