Skip to content
This repository has been archived by the owner on Aug 18, 2020. It is now read-only.

Commit

Permalink
Merge pull request #3590 from input-output-hk/adinapoli/cbr-419/fix-l…
Browse files Browse the repository at this point in the history
…ogic-bug

[CBR-419] Enforce invariant on defaultHdAddressWith
  • Loading branch information
adinapoli-iohk authored Sep 13, 2018
2 parents 823b203 + 19b41ce commit 122a9d5
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 14 deletions.
3 changes: 3 additions & 0 deletions src/Cardano/Wallet/Kernel/DB/HdWallet/Create.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import qualified Cardano.Wallet.Kernel.DB.Util.IxSet as IxSet
data CreateHdRootError =
-- | We already have a wallet with the specified ID
CreateHdRootExists HdRootId
| CreateHdRootDefaultAddressDerivationFailed

-- | Errors thrown by 'createHdAccount'
data CreateHdAccountError =
Expand Down Expand Up @@ -183,6 +184,8 @@ initHdAddress addrId address = HdAddress {
instance Buildable CreateHdRootError where
build (CreateHdRootExists rootId)
= bprint ("CreateHdRootError::CreateHdRootExists "%build) rootId
build CreateHdRootDefaultAddressDerivationFailed
= bprint "CreateHdRootError::CreateHdRootDefaultAddressDerivationFailed"

instance Buildable CreateHdAccountError where
build (CreateHdAccountUnknownRoot (UnknownHdRoot rootId))
Expand Down
20 changes: 20 additions & 0 deletions src/Cardano/Wallet/Kernel/Decrypt.hs
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
module Cardano.Wallet.Kernel.Decrypt
( decryptAddress
, decryptHdLvl2DerivationPath
, keyToWalletDecrCredentials
, WalletDecrCredentials
, WalletDecrCredentialsKey(..)
) where

import Universum

import Data.List ((!!))

import Pos.Wallet.Web.Tracking.Decrypt

import Cardano.Wallet.Kernel.DB.HdWallet (HdAccountIx (..),
HdAddressIx (..))
import Pos.Core (Address, aaPkDerivationPath, addrAttributesUnwrapped)
import Pos.Crypto (HDPassphrase, unpackHDAddressAttr)


decryptHdLvl2DerivationPath :: HDPassphrase
-> Address
-> Maybe (HdAccountIx, HdAddressIx)
decryptHdLvl2DerivationPath hdPass addr = do
hdPayload <- aaPkDerivationPath $ addrAttributesUnwrapped addr
derPath <- unpackHDAddressAttr hdPass hdPayload
guard $ length derPath == 2
pure (HdAccountIx (derPath !! 0), HdAddressIx (derPath !! 1))
41 changes: 27 additions & 14 deletions src/Cardano/Wallet/Kernel/Wallets.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import qualified Formatting.Buildable
import Data.Acid.Advanced (update')

import Pos.Core (Address, Timestamp)
import Pos.Crypto (EncryptedSecretKey, PassPhrase,
import Pos.Crypto (EncryptedSecretKey, HDPassphrase, PassPhrase,
changeEncPassphrase, checkPassMatches, emptyPassphrase,
firstHardened, safeDeterministicKeyGen)

Expand All @@ -40,6 +40,8 @@ import Cardano.Wallet.Kernel.DB.HdWallet (AssuranceLevel,
import qualified Cardano.Wallet.Kernel.DB.HdWallet as HD
import qualified Cardano.Wallet.Kernel.DB.HdWallet.Create as HD
import Cardano.Wallet.Kernel.DB.InDb (InDb (..), fromDb)
import Cardano.Wallet.Kernel.Decrypt (WalletDecrCredentialsKey (..),
decryptHdLvl2DerivationPath, keyToWalletDecrCredentials)
import Cardano.Wallet.Kernel.Internal (PassiveWallet, walletKeystore,
wallets)
import qualified Cardano.Wallet.Kernel.Keystore as Keystore
Expand Down Expand Up @@ -204,6 +206,8 @@ createHdWallet pw mnemonic spendingPassword assuranceLevel walletName = do
-- Fix properly as part of [CBR-404].
Left e@(HD.CreateHdRootExists _) ->
return . Left $ CreateWalletFailed e
Left e@(HD.CreateHdRootDefaultAddressDerivationFailed) ->
return . Left $ CreateWalletFailed e

Right hdRoot -> return (Right hdRoot)

Expand Down Expand Up @@ -239,14 +243,18 @@ createWalletHdRnd pw hasSpendingPassword defaultCardanoAddress name assuranceLev
assuranceLevel
created

hdAddress = defaultHdAddressWith rootId defaultCardanoAddress

-- We now have all the date we need to atomically generate a new
-- wallet with a default account & address.
res <- case createWallet newRoot (defaultHdAccountId rootId) hdAddress of
Left create -> update' (pw ^. wallets) create
Right restore -> update' (pw ^. wallets) restore
return $ either Left (const (Right newRoot)) res
hdPass = fst $ keyToWalletDecrCredentials (KeyForRegular esk)
hdAddress = defaultHdAddressWith hdPass rootId defaultCardanoAddress

case hdAddress of
Nothing -> return (Left HD.CreateHdRootDefaultAddressDerivationFailed)
Just addr -> do
-- We now have all the date we need to atomically generate a new
-- wallet with a default account & address.
res <- case createWallet newRoot (defaultHdAccountId rootId) addr of
Left create -> update' (pw ^. wallets) create
Right restore -> update' (pw ^. wallets) restore
return $ either Left (const (Right newRoot)) res
where

hdSpendingPassword :: InDb Timestamp -> HD.HasSpendingPassword
Expand All @@ -267,11 +275,16 @@ defaultHdAddress esk spendingPassword rootId =

-- | Given a Cardano 'Address', it returns a default 'HdAddress' at a fixed
-- and predictable generation path.
defaultHdAddressWith :: HD.HdRootId -> Address -> HdAddress
defaultHdAddressWith rootId cardanoAddress =
let hdAccountId = defaultHdAccountId rootId
hdAddressId = HdAddressId hdAccountId (HdAddressIx firstHardened)
in HD.HdAddress hdAddressId (InDb cardanoAddress)
-- module Cardano.Wallet.Kernel.Decrypt
defaultHdAddressWith :: HDPassphrase
-> HD.HdRootId
-> Address
-> Maybe HdAddress
defaultHdAddressWith hdPass rootId cardanoAddress = do
(hdAccountIx, hdAddressIx) <- decryptHdLvl2DerivationPath hdPass cardanoAddress
let hdAccountId = HdAccountId rootId hdAccountIx
hdAddressId = HdAddressId hdAccountId hdAddressIx
pure $ HD.HdAddress hdAddressId (InDb cardanoAddress)

defaultHdAccountId :: HdRootId -> HdAccountId
defaultHdAccountId rootId = HdAccountId rootId (HdAccountIx firstHardened)
Expand Down

0 comments on commit 122a9d5

Please sign in to comment.