Skip to content

Commit

Permalink
extend SharedState
Browse files Browse the repository at this point in the history
  • Loading branch information
paweljakubas committed Sep 27, 2023
1 parent c35fad6 commit adcc04e
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ data SharedState (n :: NetworkDiscriminant) k = SharedState
-- ^ Reward account script hash associated with this wallet
, poolGap :: !AddressPoolGap
-- ^ Address pool gap to be used in the address pool of shared state
, oneChangeAddressMode :: Bool
-- ^ One change address mode. If switched on then next transactions will
-- use the same change address. If no then next change index for
-- each next transaction is used
, ready :: !(Readiness (SharedAddressPools k))
-- ^ Readiness status of the shared state.
-- The state is ready if all cosigner public keys have been obtained.
Expand All @@ -289,14 +293,15 @@ deriving instance ( Show (k 'AccountK XPub) ) => Show (SharedState n k)
-- because there is no general equality for address pools
-- (we cannot test the generators for equality).
instance Eq (k 'AccountK XPub) => Eq (SharedState n k) where
SharedState a1 a2 a3 a4 a5 a6 ap == SharedState b1 b2 b3 b4 b5 b6 bp
SharedState a1 a2 a3 a4 a5 a6 a7 ap == SharedState b1 b2 b3 b4 b5 b6 b7 bp
= and
[ a1 == b1
, a2 == b2
, a3 == b3
, a4 == b4
, a5 == b5
, a6 == b6
, a7 == b7
, ap `match` bp
]
where
Expand All @@ -313,6 +318,7 @@ instance PersistPublicKey (k 'AccountK) => Buildable (SharedState n k) where
<> indentF 4 ("delegationTemplate:" <> build (delegationTemplate st))
<> indentF 4 ("rewardAccountKey:" <> build (toText <$> rewardAccountKey st))
<> indentF 4 ("poolGap:" <> build (toText $ poolGap st))
<> indentF 4 ("one change address mode:" <> build (oneChangeAddressMode st))
<> indentF 4 ("ready: " <> readyF (ready st))
where
readyF (Pending) = "Pending"
Expand Down
6 changes: 4 additions & 2 deletions lib/wallet/api/http/Cardano/Wallet/Api/Http/Shelley/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,8 @@ postSharedWalletFromRootXPrv ctx generateKey body = do
ix' <- liftHandler $ withExceptT ErrConstructSharedWalletInvalidIndex $
W.guardHardIndex ix
let state = mkSharedStateFromRootXPrv kF
(RootCredentials rootXPrv pwdP) ix' g pTemplate dTemplateM
(RootCredentials rootXPrv pwdP) ix' oneAddrMode
g pTemplate dTemplateM
let stateReadiness = state ^. #ready
if stateReadiness == Shared.Pending
then void $ liftHandler $ createNonRestoringWalletWorker @_ @s ctx wid
Expand Down Expand Up @@ -1121,6 +1122,7 @@ postSharedWalletFromRootXPrv ctx generateKey body = do
scriptValidation =
maybe RecommendedValidation getApiT (body ^. #scriptValidation)
genesisParams = ctx ^. #netParams
oneAddrMode = fromMaybe False (body ^. #oneChangeAddressMode)

postSharedWalletFromAccountXPub
:: forall ctx s k n.
Expand Down Expand Up @@ -1152,7 +1154,7 @@ postSharedWalletFromAccountXPub ctx liftKey body = do
acctIx <- liftHandler $ withExceptT ErrConstructSharedWalletInvalidIndex $
W.guardHardIndex ix
let state = mkSharedStateFromAccountXPub kF
(liftKey accXPub) acctIx g pTemplate dTemplateM
(liftKey accXPub) acctIx False g pTemplate dTemplateM
let stateReadiness = state ^. #ready
if stateReadiness == Shared.Pending
then void $ liftHandler $ createNonRestoringWalletWorker @_ @s ctx wid
Expand Down
2 changes: 1 addition & 1 deletion lib/wallet/api/http/Cardano/Wallet/Api/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1614,7 +1614,7 @@ data ApiSharedWalletPostDataFromMnemonics =
, paymentScriptTemplate :: !ApiScriptTemplateEntry
, delegationScriptTemplate :: !(Maybe ApiScriptTemplateEntry)
, scriptValidation :: !(Maybe (ApiT ValidationLevel))
, oneChangeAddress :: !(Maybe Bool)
, oneChangeAddressMode :: !(Maybe Bool)
}
deriving (Eq, Generic, Show)
deriving (FromJSON, ToJSON)
Expand Down
9 changes: 6 additions & 3 deletions lib/wallet/src/Cardano/Wallet/Address/Keys/Shared.hs
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,20 @@ mkSharedStateFromAccountXPub
=> KeyFlavorS k
-> k 'AccountK XPub
-> Index 'Hardened 'AccountK
-> Bool
-> AddressPoolGap
-> ScriptTemplate
-> Maybe ScriptTemplate
-> SharedState n k
mkSharedStateFromAccountXPub kF accXPub accIx gap pTemplate dTemplateM =
mkSharedStateFromAccountXPub kF accXPub accIx modeOnOff gap pTemplate dTemplateM =
activate kF $ SharedState
{ derivationPrefix = DerivationPrefix (purposeCIP1854, coinTypeAda, accIx)
, accountXPub = accXPub
, paymentTemplate = pTemplate
, delegationTemplate = dTemplateM
, rewardAccountKey = Nothing
, poolGap = gap
, oneChangeAddressMode = modeOnOff
, ready = Pending
}

Expand All @@ -116,12 +118,13 @@ mkSharedStateFromRootXPrv
=> KeyFlavorS k
-> ClearCredentials k
-> Index 'Hardened 'AccountK
-> Bool
-> AddressPoolGap
-> ScriptTemplate
-> Maybe ScriptTemplate
-> SharedState n k
mkSharedStateFromRootXPrv kF (RootCredentials rootXPrv pwd) accIx =
mkSharedStateFromAccountXPub kF accXPub accIx
mkSharedStateFromRootXPrv kF (RootCredentials rootXPrv pwd) accIx modeOnOff =
mkSharedStateFromAccountXPub kF accXPub accIx modeOnOff
where
accXPub = publicKey kF $ deriveAccountPrivateKey pwd rootXPrv accIx

Expand Down
1 change: 1 addition & 0 deletions lib/wallet/src/Cardano/Wallet/DB/Sqlite/Schema.hs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ SharedState
sharedStateDelegationScript (Script Cosigner) Maybe sql=delegation_script
sharedStateRewardAccount W.RewardAccount Maybe sql=reward_account
sharedStateDerivationPrefix W.DerivationPrefix sql=derivation_prefix
sharedStateOneChangeAddrMode Bool sql=one_change_addr_mode

Primary sharedStateWalletId
Foreign Wallet OnDeleteCascade shared_state sharedStateWalletId
Expand Down
11 changes: 6 additions & 5 deletions lib/wallet/src/Cardano/Wallet/DB/Store/Checkpoints/Store.hs
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,8 @@ instance

insertPrologue wid (SharedPrologue st) = do
let Shared.SharedState prefix accXPub pTemplate dTemplateM rewardAcctM
gap readiness = st
insertSharedState prefix accXPub gap pTemplate dTemplateM rewardAcctM
gap modeOnOff readiness = st
insertSharedState prefix accXPub gap pTemplate dTemplateM rewardAcctM modeOnOff
insertCosigner (cosigners pTemplate) Payment
when (isJust dTemplateM) $
insertCosigner (cosigners $ fromJust dTemplateM) Delegation
Expand All @@ -510,7 +510,7 @@ instance
deleteWhere [SharedStatePendingWalletId ==. wid]
dbChunked insertMany_ (mkSharedStatePendingIxs pendingIxs)
where
insertSharedState prefix accXPub gap pTemplate dTemplateM rewardAcctM =
insertSharedState prefix accXPub gap pTemplate dTemplateM rewardAcctM modeOnOff =
do
deleteWhere [SharedStateWalletId ==. wid]
insert_ $ SharedState
Expand All @@ -521,6 +521,7 @@ instance
, sharedStateDelegationScript = template <$> dTemplateM
, sharedStateRewardAccount = rewardAcctM
, sharedStateDerivationPrefix = prefix
, sharedStateOneChangeAddrMode = modeOnOff
}

insertCosigner cs cred = do
Expand Down Expand Up @@ -555,7 +556,7 @@ instance

loadPrologue wid = runMaybeT $ do
st <- MaybeT $ selectFirst [SharedStateWalletId ==. wid] []
let SharedState _ accountBytes gap pScript dScriptM rewardAcctM prefix =
let SharedState _ accountBytes gap pScript dScriptM rewardAcctM prefix modeOnOff =
entityVal st
let accXPub = unsafeDeserializeXPub accountBytes
pCosigners <- lift $ selectCosigners @key wid Payment
Expand All @@ -568,7 +569,7 @@ instance
ScriptTemplate (Map.fromList $ prepareKeys dCosigners)
<$> dScriptM
mkSharedState =
Shared.SharedState prefix accXPub pTemplate dTemplateM rewardAcctM gap
Shared.SharedState prefix accXPub pTemplate dTemplateM rewardAcctM gap modeOnOff
pendingIxs <- lift selectSharedStatePendingIxs
prologue <- lift $ multisigPoolAbsent wid <&> \case
True -> mkSharedState Shared.Pending
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ mkSharedStateFromAccountXPub'
:: HasSNetworkId n
=> SharedKey 'AccountK XPub
-> Index 'Hardened 'AccountK
-> Bool
-> AddressPoolGap
-> ScriptTemplate
-> Maybe ScriptTemplate
Expand All @@ -145,7 +146,7 @@ prop_addressWithScriptFromOurVerKeyIxIn (CatalystSharedState accXPub' accIx' pTe
keyIx' === keyIx
where
addr = constructAddressFromIx @n UtxoExternal pTemplate' dTemplate' keyIx
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' g pTemplate' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' False g pTemplate' dTemplate'
(Just (keyIx', _), _) = isShared @n addr sharedState

prop_addressWithScriptFromOurVerKeyIxBeyond
Expand All @@ -159,7 +160,7 @@ prop_addressWithScriptFromOurVerKeyIxBeyond (CatalystSharedState accXPub' accIx'
snd (isShared @n addr sharedState) === sharedState
where
addr = constructAddressFromIx @n UtxoExternal pTemplate' dTemplate' keyIx
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' g pTemplate' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' False g pTemplate' dTemplate'

getAddrPool
:: SharedState n k
Expand All @@ -178,7 +179,7 @@ prop_addressDiscoveryMakesAddressUsed (CatalystSharedState accXPub' accIx' pTemp
(snd <$> Map.lookup addr ourAddrs) === Just Used .&&.
fromIntegral (Map.size ourAddrs) === (fromIntegral (fromEnum ix + 1) + getAddressPoolGap g)
where
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' g pTemplate' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' False g pTemplate' dTemplate'
addr = AddressPool.addressFromIx (getAddrPool sharedState) keyIx
(Just (ix, _), sharedState') = isShared @n (liftPaymentAddress @n addr) sharedState
ourAddrs = AddressPool.addresses (getAddrPool sharedState')
Expand All @@ -194,7 +195,7 @@ prop_addressDoubleDiscovery (CatalystSharedState accXPub' accIx' pTemplate' dTem
snd sharedState' === snd sharedState''
where
addr = constructAddressFromIx @n UtxoExternal pTemplate' dTemplate' keyIx
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' g pTemplate' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' False g pTemplate' dTemplate'
sharedState' = isShared @n addr sharedState
sharedState'' = isShared @n addr (snd sharedState')

Expand All @@ -213,7 +214,7 @@ prop_addressDiscoveryImpossibleFromOtherAccXPub (CatalystSharedState _ accIx' pT
(ScriptTemplate _ script') = pTemplate'
pTemplate'' = ScriptTemplate
(Map.fromList [(Cosigner 0, getRawKey SharedKeyS accXPub')]) script'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' g pTemplate'' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' False g pTemplate'' dTemplate'

prop_addressDiscoveryImpossibleFromOtherAccountOfTheSameRootXPrv
:: forall n. HasSNetworkId n
Expand All @@ -235,7 +236,7 @@ prop_addressDiscoveryImpossibleFromOtherAccountOfTheSameRootXPrv (CatalystShared
(Map.fromList [(Cosigner 0, getRawKey SharedKeyS accXPub')]) script'
pTemplate''' = ScriptTemplate
(Map.fromList [(Cosigner 0, getRawKey SharedKeyS accXPub'')]) script'
sharedState = mkSharedStateFromAccountXPub' @n accXPub'' accIx'' g pTemplate'' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub'' accIx'' False g pTemplate'' dTemplate'
addr = constructAddressFromIx @n UtxoExternal pTemplate''' dTemplate' keyIx

prop_addressDiscoveryImpossibleWithinAccountButDifferentScript
Expand All @@ -251,7 +252,7 @@ prop_addressDiscoveryImpossibleWithinAccountButDifferentScript (CatalystSharedSt
where
(ScriptTemplate cosignerXpubs _) = pTemplate'
pTemplate'' = ScriptTemplate cosignerXpubs script'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' g pTemplate' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' False g pTemplate' dTemplate'
addr = constructAddressFromIx @n UtxoExternal pTemplate'' dTemplate' keyIx

prop_addressDiscoveryDoesNotChangeGapInvariance
Expand All @@ -263,7 +264,7 @@ prop_addressDiscoveryDoesNotChangeGapInvariance (CatalystSharedState accXPub' ac
preconditions keyIx g dTemplate' ==>
fromIntegral (L.length mapOfConsecutiveUnused) === getAddressPoolGap g
where
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' g pTemplate' dTemplate'
sharedState = mkSharedStateFromAccountXPub' @n accXPub' accIx' False g pTemplate' dTemplate'
addr = AddressPool.addressFromIx (getAddrPool sharedState) keyIx
(_, sharedState') = isShared @n (liftPaymentAddress @n addr) sharedState
mapOfConsecutiveUnused
Expand Down Expand Up @@ -395,5 +396,5 @@ instance Arbitrary (SharedState 'Mainnet SharedKey) where
accIx' <- arbitrary
scriptTemplate <- genScriptTemplate
pure $ mkSharedStateFromRootXPrv SharedKeyS
(RootCredentials rootXPrv pwd) accIx'
(RootCredentials rootXPrv pwd) accIx' False
defaultAddressPoolGap scriptTemplate Nothing
1 change: 1 addition & 0 deletions lib/wallet/test/unit/Cardano/Wallet/DB/Arbitrary.hs
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ instance Arbitrary (SharedState 'Mainnet SharedKey) where
Nothing
Nothing
defaultAddressPoolGap
False
(Shared.Active $ SharedAddressPools
(Shared.newSharedAddressPool @'Mainnet defaultAddressPoolGap pt Nothing)
(Shared.newSharedAddressPool @'Mainnet defaultAddressPoolGap pt Nothing)
Expand Down

0 comments on commit adcc04e

Please sign in to comment.