Test client: Don't allow password change if there are pending local wallet changes.

This is in line with:

https://github.com/orblivion/lbry-wallet-sync-draft/blob/master/spec/user-flows.md#push-local-password-change

This is the only rule we have to go out of our way to implement, and it's for UI simplicity, and/or to keep the hierarchy consistent. The rest of the rules you see there sort of automatically get enforced with the existing guardrails.
This commit is contained in:
Daniel Krol 2022-07-08 12:36:10 -04:00
parent a9f88a552c
commit f9e3013e64
3 changed files with 127 additions and 31 deletions

View file

@ -29,9 +29,9 @@ Now that the account exists, grab an auth token with both clients.
```
>>> c1.get_auth_token()
Got auth token: d7159a5a84d97cdb02c642ad5d866ebfb5f69e390c873591a5620e3614d0bdeb
Got auth token: e244aae31bb2070d9269c14706a3a352ddda5e090fefc315bd4d28b8bc787278
>>> c2.get_auth_token()
Got auth token: 9170ffc5ec3a581623bb3b17efcce3d261cb6ab480be1b295c25921fdfd8bd3c
Got auth token: c77afe32288a9bf45e55b8fba5aca2b9d3388a277ad89db6fff179337afbd62b
```
## Syncing
@ -43,7 +43,7 @@ Create a new wallet + metadata (we'll wrap it in a struct we'll call `WalletStat
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6EMrhL3U4HXiCJZbTyV3fAgA5XFG3C0Qwak7t/g1QBQHjpztK98587mSN5e+MNJ3+a9ydQi9q+piyLqA79WjsnyOsUKJTlGbrsVXqEzJo/mvUdb4HtDa0MaK2arvl8RD+hqsiqP/G5PVOO0JIfl3A15QHbA5/GsY8zG3xqQK95Zg=')
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6+oSc2AE5FY971fW2kQqFvXnen5RD8RU9pMjaKEnvFE8XrdXXogVooiu9Q/099eT8Y9UePoER/aphmzJBb/fwNTOWanFsPCdEObmwfuL1OLPJ+FuAJ07am8TUSJEy12yuMqtQSj6kVF2aMa4oABthKaZ00sx98HkkdUo6sWedY0o=')
'Success'
```
@ -54,8 +54,8 @@ Now, call `init_wallet_state` with the other client. Then, we call `get_remote_w
```
>>> c2.init_wallet_state()
>>> c2.get_remote_wallet()
Got (and maybe merged in) latest walletState:
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6EMrhL3U4HXiCJZbTyV3fAgA5XFG3C0Qwak7t/g1QBQHjpztK98587mSN5e+MNJ3+a9ydQi9q+piyLqA79WjsnyOsUKJTlGbrsVXqEzJo/mvUdb4HtDa0MaK2arvl8RD+hqsiqP/G5PVOO0JIfl3A15QHbA5/GsY8zG3xqQK95Zg=')
Got latest walletState:
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6+oSc2AE5FY971fW2kQqFvXnen5RD8RU9pMjaKEnvFE8XrdXXogVooiu9Q/099eT8Y9UePoER/aphmzJBb/fwNTOWanFsPCdEObmwfuL1OLPJ+FuAJ07am8TUSJEy12yuMqtQSj6kVF2aMa4oABthKaZ00sx98HkkdUo6sWedY0o=')
'Success'
```
@ -67,11 +67,12 @@ Push a new version, GET it with the other client. Even though we haven't edited
>>> c2.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6hb2Qt8BCiLujMT0ykatcAvuVhW7uMuVbhSONFhQkLQwhZ+qBlYyTxmLc+tGzwmRLPYWCbfWY+oDcHE90h9wEKwGjNyDdjybkBRPvt4ufyIyYV/a3UPCvVYgdvktBRUF8fBagTQR2V/FQwXEeNYAAx53YSQQfy7FTYnjT2wVlbww=')
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6mTAOkeMQKuJWirqfyDBjzvneKqcDdNO7UzZ2EdGFs1iW89WMU5UxL//hetnIcXLFFh0SqUjCfj5heyLKEvYY5wJQ0cmIJZEAiPFIZWUjju8J8UEeRl5JWW89x3qhUNrog5a7PnIi/AIRAm6tl7gfzMoujHBWiLPM4xKOO8wX9dw=')
'Success'
>>> c1.get_remote_wallet()
Got (and maybe merged in) latest walletState:
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6hb2Qt8BCiLujMT0ykatcAvuVhW7uMuVbhSONFhQkLQwhZ+qBlYyTxmLc+tGzwmRLPYWCbfWY+oDcHE90h9wEKwGjNyDdjybkBRPvt4ufyIyYV/a3UPCvVYgdvktBRUF8fBagTQR2V/FQwXEeNYAAx53YSQQfy7FTYnjT2wVlbww=')
Nothing to merge. Taking remote walletState as latest walletState.
Got latest walletState:
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6mTAOkeMQKuJWirqfyDBjzvneKqcDdNO7UzZ2EdGFs1iW89WMU5UxL//hetnIcXLFFh0SqUjCfj5heyLKEvYY5wJQ0cmIJZEAiPFIZWUjju8J8UEeRl5JWW89x3qhUNrog5a7PnIi/AIRAm6tl7gfzMoujHBWiLPM4xKOO8wX9dw=')
'Success'
```
@ -97,11 +98,12 @@ The wallet is synced between the clients. The client with the changed preference
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6Boe8tNSgXWgoCDHDdCaLWauz6UEF2NqgjvdszFkFEOEgRIg3TYSIM2IncYG6JzeY/jjcSVAdARZ2mhW2qu2w42O2KUR53B7272YCohRUQjTG2VGj3r8idt6RF3gdJz4kPTvj9Mb2hHgxLLEsmpGrH5sAoVtnctP4kkbw4tt9yTMenzxBf330eN0kBikHMRDS')
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6uTrpDaroi9aQ0D5rtu8kietZspbFSlyQyEqqfRKA+bMp4Ob7VK3lznxByGs67IpPm2Z0ZorMzaNzkuCghXh/N6YDjQFhZTUWxVo9N10M1bi++2rq2tK4iagARbWPar+Ju8zba2UcknOLZKzphYU1t8EXPykpZUonXO894ljOb2kKEs7eltudGvdRB2DqNgH2')
'Success'
>>> c2.get_remote_wallet()
Got (and maybe merged in) latest walletState:
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6Boe8tNSgXWgoCDHDdCaLWauz6UEF2NqgjvdszFkFEOEgRIg3TYSIM2IncYG6JzeY/jjcSVAdARZ2mhW2qu2w42O2KUR53B7272YCohRUQjTG2VGj3r8idt6RF3gdJz4kPTvj9Mb2hHgxLLEsmpGrH5sAoVtnctP4kkbw4tt9yTMenzxBf330eN0kBikHMRDS')
Nothing to merge. Taking remote walletState as latest walletState.
Got latest walletState:
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6uTrpDaroi9aQ0D5rtu8kietZspbFSlyQyEqqfRKA+bMp4Ob7VK3lznxByGs67IpPm2Z0ZorMzaNzkuCghXh/N6YDjQFhZTUWxVo9N10M1bi++2rq2tK4iagARbWPar+Ju8zba2UcknOLZKzphYU1t8EXPykpZUonXO894ljOb2kKEs7eltudGvdRB2DqNgH2')
'Success'
>>> c2.get_preferences()
{'animal': 'cow', 'car': ''}
@ -128,7 +130,7 @@ One client POSTs its change first.
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE62nX6KIGR6GewHaJNGyA4hgu8Ce4mX6RTTjEHZE1NJ+ABlxz88639N/56ybBHIN8Ztcb33kLcsz+YWxn5esLVkjoEl49It6VK5mIFkUtL9QVGvMaFExUD3+l7v6USq3U92Aulu/l20WB2ZV0IqXZ7KX+GN54Yez/Vv9diQwyUujZa5n5+yoU7sY45rQ0xwmTS')
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE6QQcktx8tncvrkjGJZk7o37IZ26AsGJnNLif2JiPIZnyRkINakzeU57cryvom9pG0qVdFFdDTAKKIreEj//yJt4pj40rhdsQ8nX6qCuN0nkcHtnpCNcTSmXlRfC/4WDfL5Mq5/HWYVVeQ54GlPp3n2Fj9910TlXVRibp6RO2P98f6cEP8kHM7s+efgLtCRmVK')
'Success'
```
@ -138,8 +140,9 @@ Eventually, the client will be responsible (or at least more responsible) for me
```
>>> c2.get_remote_wallet()
Got (and maybe merged in) latest walletState:
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE62nX6KIGR6GewHaJNGyA4hgu8Ce4mX6RTTjEHZE1NJ+ABlxz88639N/56ybBHIN8Ztcb33kLcsz+YWxn5esLVkjoEl49It6VK5mIFkUtL9QVGvMaFExUD3+l7v6USq3U92Aulu/l20WB2ZV0IqXZ7KX+GN54Yez/Vv9diQwyUujZa5n5+yoU7sY45rQ0xwmTS')
Merging local changes with remote changes to create latest walletState.
Got latest walletState:
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE6QQcktx8tncvrkjGJZk7o37IZ26AsGJnNLif2JiPIZnyRkINakzeU57cryvom9pG0qVdFFdDTAKKIreEj//yJt4pj40rhdsQ8nX6qCuN0nkcHtnpCNcTSmXlRfC/4WDfL5Mq5/HWYVVeQ54GlPp3n2Fj9910TlXVRibp6RO2P98f6cEP8kHM7s+efgLtCRmVK')
'Success'
>>> c2.get_preferences()
{'animal': 'horse', 'car': 'Audi'}
@ -151,11 +154,12 @@ Finally, the client with the merged wallet pushes it to the server, and the othe
>>> c2.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6yRz92fRLp8UCOZ0jfNwkY2ZnCS5DSdzt06++co48MSWvKLhflrjpqBbwup4QWHB9O+1VAKoi2KPB0fbIHrnTeXLzHXkN6lPWUyOsVg61JP37FsPQBdOf7smdeImzh6bj5AT7N6qltsdYa6OdGsA2+K7syS/NJsnAE2pXLuNZWGJkDgkThH6zMiBayX2HpDeh')
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6t9OMFtRl0D4E4YJoE8zR0VuteEroiRyOUgXEhjUBuG0stbwqO/WoNuydNxmRtVMLWgHV5DUlUGZKlTBsuf/fJ6svMdUU7R34uYsSve5ioJw+FBY/w25CYRpa49YZfNhu5YOtmeLHF7AuTMBoc2kkyJj0Jg0IhjqfORIQiifW0YwaWh/eEch9Kzxi+d5DGMaL')
'Success'
>>> c1.get_remote_wallet()
Got (and maybe merged in) latest walletState:
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6yRz92fRLp8UCOZ0jfNwkY2ZnCS5DSdzt06++co48MSWvKLhflrjpqBbwup4QWHB9O+1VAKoi2KPB0fbIHrnTeXLzHXkN6lPWUyOsVg61JP37FsPQBdOf7smdeImzh6bj5AT7N6qltsdYa6OdGsA2+K7syS/NJsnAE2pXLuNZWGJkDgkThH6zMiBayX2HpDeh')
Nothing to merge. Taking remote walletState as latest walletState.
Got latest walletState:
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6t9OMFtRl0D4E4YJoE8zR0VuteEroiRyOUgXEhjUBuG0stbwqO/WoNuydNxmRtVMLWgHV5DUlUGZKlTBsuf/fJ6svMdUU7R34uYsSve5ioJw+FBY/w25CYRpa49YZfNhu5YOtmeLHF7AuTMBoc2kkyJj0Jg0IhjqfORIQiifW0YwaWh/eEch9Kzxi+d5DGMaL')
'Success'
>>> c1.get_preferences()
{'animal': 'horse', 'car': 'Audi'}
@ -186,7 +190,7 @@ We try to POST both of them to the server. The second one fails because of the c
>>> c2.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE67VjoKcDba0+yJBoEasS8RKGHH8c7JbShgv+lf3CVnHXPFsA45Y3zmvyLEIsvpUxmg/jE5rw/jsh1ZCNt/yKOjRhyR8VFwR69hPl3n5j+2ya1tu4G++7REfriAkRw4kHP1im5NJ0WXPMIvdM2bV+nTFqLMdqxySyF1ljsXEdhtu9cw8A4Qs1DYOPPKfewtHNF')
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6/mE/7xT6rZ8h11dWwHMB8K+XhqNVnzgkLEx6mFntRC/HKPGbRaqeHWiQrIPUZk+Y8eJlA4FrkI/snDyO4Gbo8OI2kef7PaPV1tiL9GVYbwPoD+/KQsb1RwMVkNMHiRhJyerMzX2e5DHOBZ8a9/gtY5QROKq17OF9I6WAbW4Kt+oyAMvwPhvr53K3PAgkUZZO')
'Success'
>>> c1.update_remote_wallet()
Submitted wallet is out of date.
@ -200,15 +204,16 @@ The client that is out of date will then call `get_remote_wallet`, which GETs an
```
>>> c1.get_remote_wallet()
Got (and maybe merged in) latest walletState:
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE67VjoKcDba0+yJBoEasS8RKGHH8c7JbShgv+lf3CVnHXPFsA45Y3zmvyLEIsvpUxmg/jE5rw/jsh1ZCNt/yKOjRhyR8VFwR69hPl3n5j+2ya1tu4G++7REfriAkRw4kHP1im5NJ0WXPMIvdM2bV+nTFqLMdqxySyF1ljsXEdhtu9cw8A4Qs1DYOPPKfewtHNF')
Merging local changes with remote changes to create latest walletState.
Got latest walletState:
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6/mE/7xT6rZ8h11dWwHMB8K+XhqNVnzgkLEx6mFntRC/HKPGbRaqeHWiQrIPUZk+Y8eJlA4FrkI/snDyO4Gbo8OI2kef7PaPV1tiL9GVYbwPoD+/KQsb1RwMVkNMHiRhJyerMzX2e5DHOBZ8a9/gtY5QROKq17OF9I6WAbW4Kt+oyAMvwPhvr53K3PAgkUZZO')
'Success'
>>> c1.get_preferences()
{'animal': 'beaver', 'car': 'Toyota'}
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=7, encrypted_wallet='czo4MTkyOjE2OjE6+PrieMsaswjsA5TXASYa2MwLHJEYHCAypDagR95NmAVI7/SefVs8aF1s7mA/CMTLiV3N1qwyzLMXpOxSbEiBLvjgOL00ajrHLw/ZPmOOToFIul4/9Jw5mTnqisdRWBaAF2yzXsflY2zQFllmSBJPRAiWAZ0xaErW+SJhKZzHK/aBg2PC9v1GFR7lZXpqx4CQ')
WalletState(sequence=7, encrypted_wallet='czo4MTkyOjE2OjE6Xph2n4tSYT7iRhBsLn99bykQNuFI8oWckzuWcF5nUbl2GcJ53n32YnMSNtQLfuyt0oCjSSXS7BBq9uQSPQKWANBAN6MynSQzQ3UIEsxq6ExtdE1Ua22umxmxeo8vn/xYN6CaLnl0Bji1V7HlOztzRpZSml7ZVoNtbMf8iwThdOj4XR3EMElcHowQY2zd+Tzn')
'Success'
```
@ -226,7 +231,7 @@ Generating keys...
Done generating keys
Successfully updated password and wallet state on server
Synced walletState:
WalletState(sequence=8, encrypted_wallet='czo4MTkyOjE2OjE6/S99ffv8LCcu1Xk9jLjROv4tQ/nUJnxkazOfVg+eTCBOB0WiGvPKTPzo4QkmpDsNa4N3ZHHIFfwz+xG4Q+xMuWlBU38Ok6Igqtc/du6/IzQxRkUumm49s8xaFeFqQB+mqawq89RB9UDMjYlzvSDPD7ZAgxpCXkT5oIuIqkGqnc9XlIStDAlisIfNs67Orrja')
WalletState(sequence=8, encrypted_wallet='czo4MTkyOjE2OjE6xxIydbWzxcZ2e7OivUevFO98qzS/Fy/bag0IN5/Ecm8GDEgEY84deAli9YiVxCTbwuMM1qAaL9wuC/Rj8fU9FykmAa8YEghEfIiuOTPyaySgSvDp2JY6gdZ+N+fx7qkJfzXshz5q5TuMdztWCouh4sCoaV2c+Gl7ieijq6A0c4lccOTUur+LX1mrEC5KP9Zs')
'Success'
```
@ -247,7 +252,7 @@ The client that changed its password can easily get a new token because it has t
```
>>> c1.get_auth_token()
Got auth token: fc40aea0ba6193f0c1903c0c95ed27010a50cea5176c75813c90ff9eb56996f8
Got auth token: 3d5227f7873a43fecb991e5026d413142541720f33ca92898acf2c8b1cdeb20d
>>> c2.get_auth_token()
Error 401
b'{"error":"Unauthorized: No match for email and password"}\n'
@ -255,5 +260,29 @@ b'{"error":"Unauthorized: No match for email and password"}\n'
Generating keys...
Done generating keys
>>> c2.get_auth_token()
Got auth token: 9230030eac6107b889e82d2abb0d4be189680d3882a44e055ac7a1c9db30e00b
Got auth token: d062d33d5692f7466f5560560fecc8e17fb903f13f5be8e4289a48a395a4306b
```
We don't allow password changes if we have pending wallet changes to push. This is to prevent a situation where the user has to merge local and remote changes in the middle of a password change.
```
>>> c1.set_preference('animal', 'leemur')
{'animal': 'leemur'}
>>> c1.change_password("starboard")
Generating keys...
Done generating keys
Local changes found. Update remote wallet before changing password.
'Failure'
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Synced walletState:
WalletState(sequence=9, encrypted_wallet='czo4MTkyOjE2OjE6i5NbYdtHfFjeIBfN1EL2nmOGlCr6hFbbPI5Y8Eq2JNeWDDy4UXTGJRNMA0SamvxneDb09RpwrW6+ffEo931rdZx0dozHCkEjKTeV5gthzbdoA7FXbiyDpJnx8DDyw2wyV/PjDKbH3dL2ojr/EgfiFivLq3FLXzopclXlL9zSipdKL3qgzN7PfRWuqiiNoY8q')
'Success'
>>> c1.change_password("starboard")
Generating keys...
Done generating keys
Successfully updated password and wallet state on server
Synced walletState:
WalletState(sequence=10, encrypted_wallet='czo4MTkyOjE2OjE6GCvOav9loezTMQiq9KD7eQ834lIcOsVum6+zakt/GAX7t527dYbQ8HFWSB2O0CGuD4R5j4P2AJC7tIhBmhNbWGeAXjDtxlDFDRE//9BsFkZLAUyxGcMaOPz/obFXNrO0lFGM456fSS1E6EX17gmkDT1T6DKPQd9oNwx8UteEBLNz8V2Cw8Aa/eBrtzlgCSMf')
'Success'
```

View file

@ -234,3 +234,14 @@ c2.get_auth_token()
c2.set_local_password("eggsandwich")
c2.get_auth_token()
""")
print("""
We don't allow password changes if we have pending wallet changes to push. This is to prevent a situation where the user has to merge local and remote changes in the middle of a password change.
""")
code_block("""
c1.set_preference('animal', 'leemur')
c1.change_password("starboard")
c1.update_remote_wallet()
c1.change_password("starboard")
""")

View file

@ -19,6 +19,16 @@ class LBRYSDK():
}))
return response.json()['result']['data']
@staticmethod
def get_hash(wallet_id):
response = requests.post('http://localhost:5279', json.dumps({
"method": "sync_hash",
"params": {
"wallet_id": wallet_id,
},
}))
return response.json()['result']
# TODO - error checking
@staticmethod
def update_wallet(wallet_id, password, data):
@ -311,8 +321,18 @@ class Client():
# won't lose any changes.
self.synced_wallet_state = WalletState(
sequence=0,
# TODO - This should be the encrypted form of the empty wallet. The very
# first baseline, which could be used for merges in weird cases where
# users make conflicting changes on two different clients before ever
# pushing to the sync server.
encrypted_wallet="",
)
# Initialize to the hash of the empty wallet. This way we will know if any
# changes to the wallet exist that haven't been pushed yet, even if the
# changes were made before the wallet state was initialized.
# TODO - actually set the right hash
self.mark_local_changes_synced_to_empty()
def register(self):
success = self.wallet_sync_api.register(
@ -355,12 +375,16 @@ class Client():
# not just a function.
# For now, the SDK handles merging (in a way that we hope to improve with
# the above eventually) so we will just return `new_wallet_state`.
#
# It would be nice to have a little "we just merged in changes" log output
# if there are local changes, just for demo purpoes. Unfortunately, the SDK
# outputs a different encrypted blob each time we ask it for the encrypted
# wallet, so there's no easy way to check if it actually changed.
# the above eventually) so we will just return `new_wallet_state`. However,
# since we can at least compare hashes, we'll leave a little note for the
# user indicating that we're doing a merge. Caveat: We can't do it on
# sequence=0 because we can't get a sense of whether changes were made on a
# client before the first sync.
if self.synced_wallet_state.sequence > 0:
if self.has_unsynced_local_changes():
print ("Merging local changes with remote changes to create latest walletState.")
else:
print ("Nothing to merge. Taking remote walletState as latest walletState.")
return new_wallet_state
# Returns: status
@ -394,7 +418,10 @@ class Client():
self.synced_wallet_state = merged_wallet_state
self.update_local_encrypted_wallet(merged_wallet_state.encrypted_wallet)
print ("Got (and maybe merged in) latest walletState:")
# We just took the value from the sync server, so local changes are synced
self.mark_local_changes_synced()
print ("Got latest walletState:")
pprint(self.synced_wallet_state)
return "Success"
@ -420,6 +447,9 @@ class Client():
# We updated it. Now it's synced and we mark it as such.
self.synced_wallet_state = submitted_wallet_state
# We just pushed our local changes to the server, so local changes are synced
self.mark_local_changes_synced()
print ("Synced walletState:")
pprint(self.synced_wallet_state)
return "Success"
@ -436,6 +466,21 @@ class Client():
new_lbry_id_password, new_sync_password, new_hmac_key = derive_secrets(new_root_password, self.salt)
if self.synced_wallet_state and self.synced_wallet_state.sequence > 0:
# Don't allow it to change if we have local changes to push. This
# precludes the possibility of having a conflict with remote changes,
# followed by a merge with user interaction, when the user is already in
# the middle of a password change. This way, if there is a conflict, we
# can simply get the latest wallet and try again with the same password
# that the user just entered, guaranteeing that they won't need to do any
# more interactions.
#
# NOTE: If for whatever reason this is removed, make sure to add a call
# to mark_local_changes_synced as appropriate below, since we may be
# going from unsynced to synced.
if self.has_unsynced_local_changes():
print("Local changes found. Update remote wallet before changing password.")
return "Failure"
# Create a *new* wallet state (with our new sync password), with the
# updated sequence, and include our local encrypted wallet changes.
# Don't set self.synced_wallet_state to this until we know that it's
@ -479,6 +524,17 @@ class Client():
# TODO - error checking
return LBRYSDK.get_preferences(self.wallet_id)
def has_unsynced_local_changes(self):
return self.lbry_sdk_last_synced_hash != LBRYSDK.get_hash(self.wallet_id)
def mark_local_changes_synced(self):
self.lbry_sdk_last_synced_hash = LBRYSDK.get_hash(self.wallet_id)
def mark_local_changes_synced_to_empty(self):
# TODO - this should be the hash of the empty wallet. See
# comment in init_wallet_state().
self.lbry_sdk_last_synced_hash = ""
def update_local_encrypted_wallet(self, encrypted_wallet):
# TODO - error checking
return LBRYSDK.update_wallet(self.wallet_id, self.sync_password, encrypted_wallet)