Skip to content

Commit d4a96d3

Browse files
authored
Don't reuse public keys, generate puzzles for all wallets (#192)
* Don't reuse public keys, generate puzzles for all wallets (100) * Use the right start and end indeces * Handle edge case with all used entries
1 parent 6ff9f01 commit d4a96d3

File tree

6 files changed

+36
-58
lines changed

6 files changed

+36
-58
lines changed

src/wallet/cc_wallet/cc_wallet_puzzles.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def get_innerpuzzle_from_puzzle(puzzle: str):
9999
def create_spend_for_ephemeral(parent_of_e, auditor_coin, spend_amount):
100100
puzstring = f"(r (r (c (q 0x{auditor_coin.name()}) (c (q {spend_amount}) (q ())))))"
101101
puzzle = Program(binutils.assemble(puzstring))
102-
coin = Coin(parent_of_e.name(), puzzle.get_tree_hash(), 0)
102+
coin = Coin(parent_of_e.name(), puzzle.get_tree_hash(), uint64(0))
103103
solution = Program(binutils.assemble("()"))
104104
coinsol = CoinSolution(coin, clvm.to_sexp_f([puzzle, solution]))
105105
return coinsol
@@ -109,7 +109,7 @@ def create_spend_for_ephemeral(parent_of_e, auditor_coin, spend_amount):
109109
def create_spend_for_auditor(parent_of_a, auditee):
110110
puzstring = f"(r (c (q 0x{auditee.name()}) (q ())))"
111111
puzzle = Program(binutils.assemble(puzstring))
112-
coin = Coin(parent_of_a.name(), puzzle.get_tree_hash(), 0)
112+
coin = Coin(parent_of_a.name(), puzzle.get_tree_hash(), uint64(0))
113113
solution = Program(binutils.assemble("()"))
114114
coinsol = CoinSolution(coin, clvm.to_sexp_f([puzzle, solution]))
115115
return coinsol
@@ -119,7 +119,7 @@ def cc_generate_eve_spend(coin: Coin, full_puzzle: Program):
119119
solution = cc_make_eve_solution(
120120
coin.parent_coin_info, coin.puzzle_hash, coin.amount
121121
)
122-
list_of_solutions = [CoinSolution(coin, clvm.to_sexp_f([full_puzzle, solution, ]), )]
122+
list_of_solutions = [CoinSolution(coin, clvm.to_sexp_f([full_puzzle, solution]),)]
123123
aggsig = BLSSignature.aggregate([])
124124
spend_bundle = SpendBundle(list_of_solutions, aggsig)
125125
return spend_bundle

src/wallet/trade_manager.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ async def create_offer_for_ids(
5959
to_exclude: List[Coin] = []
6060
else:
6161
to_exclude = spend_bundle.removals()
62-
zero_spend_bundle: Optional[SpendBundle] = await wallet.generate_zero_val_coin(
63-
False, to_exclude
64-
)
62+
zero_spend_bundle: Optional[
63+
SpendBundle
64+
] = await wallet.generate_zero_val_coin(False, to_exclude)
6565

6666
if zero_spend_bundle is None:
6767
raise ValueError(
@@ -290,7 +290,7 @@ async def respond_to_offer(self, file_path: Path) -> bool:
290290
)
291291
else:
292292
if chia_spend_bundle is None:
293-
to_exclude = []
293+
to_exclude: List = []
294294
else:
295295
to_exclude = chia_spend_bundle.removals()
296296
zero_spend_bundle: SpendBundle = await wallets[

src/wallet/wallet_puzzle_store.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -293,20 +293,3 @@ async def get_unused_derivation_path(self) -> Optional[uint32]:
293293
return uint32(row[0])
294294

295295
return None
296-
297-
async def get_unused_derivation_path_for_wallet(
298-
self, wallet_id: int
299-
) -> Optional[uint32]:
300-
"""
301-
Returns the first unused derivation path by derivation_index.
302-
"""
303-
cursor = await self.db_connection.execute(
304-
f"SELECT MIN(derivation_index) FROM derivation_paths WHERE used=0 and wallet_id={wallet_id};"
305-
)
306-
row = await cursor.fetchone()
307-
await cursor.close()
308-
309-
if row is not None and row[0] is not None:
310-
return uint32(row[0])
311-
312-
return None

src/wallet/wallet_state_manager.py

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -207,48 +207,41 @@ async def get_keys(
207207
private = self.private_key.private_child(index_for_puzzlehash).get_private_key()
208208
return pubkey, private
209209

210-
async def create_more_puzzle_hashes(
211-
self, from_zero: bool = False, for_wallet: Any = None
212-
):
210+
async def create_more_puzzle_hashes(self, from_zero: bool = False):
213211
"""
214212
For all wallets in the user store, generates the first few puzzle hashes so
215213
that we can restore the wallet from only the private keys.
216214
"""
215+
targets = list(self.wallets.keys())
217216

218-
if for_wallet is None:
219-
targets = list(self.wallets.keys())
220-
else:
221-
targets = [for_wallet]
217+
unused: Optional[uint32] = await self.puzzle_store.get_unused_derivation_path()
218+
if unused is None:
219+
# This handles the case where the database has entries but they have all been used
220+
unused = await self.puzzle_store.get_last_derivation_path()
221+
if unused is None:
222+
# This handles the case where the database is empty
223+
unused = uint32(0)
224+
225+
to_generate = 100
222226

223227
for wallet_id in targets:
224228
target_wallet = self.wallets[wallet_id]
225-
unused: Optional[
226-
uint32
227-
] = await self.puzzle_store.get_unused_derivation_path_for_wallet(wallet_id)
229+
228230
last: Optional[
229231
uint32
230232
] = await self.puzzle_store.get_last_derivation_path_for_wallet(wallet_id)
231233

232-
if target_wallet.wallet_info.type == WalletType.COLOURED_COIN:
233-
to_generate = 100
234-
else:
235-
to_generate = 500
236234
start_index = 0
237235
derivation_paths: List[DerivationRecord] = []
238236

239-
if last is None:
240-
assert unused is None
241-
if unused is not None:
242-
assert last is not None
237+
if last is not None:
243238
start_index = last + 1
244-
to_generate -= last - unused
245239

246240
# If the key was replaced (from_zero=True), we should generate the puzzle hashes for the new key
247-
end = start_index + to_generate
248241
if from_zero:
249242
start_index = 0
250243

251-
for index in range(start_index, end):
244+
for index in range(start_index, unused + to_generate):
252245
pubkey: PublicKey = self.get_public_key(uint32(index))
253246
puzzle: Program = target_wallet.puzzle_for_pk(bytes(pubkey))
254247
puzzlehash: bytes32 = puzzle.get_tree_hash()
@@ -266,8 +259,8 @@ async def create_more_puzzle_hashes(
266259
)
267260

268261
await self.puzzle_store.add_derivation_paths(derivation_paths)
269-
if from_zero and unused is not None and unused > 0:
270-
await self.puzzle_store.set_used_up_to(uint32(unused - 1))
262+
if unused > 0:
263+
await self.puzzle_store.set_used_up_to(uint32(unused - 1))
271264

272265
async def get_unused_derivation_record(self, wallet_id: uint32) -> DerivationRecord:
273266
"""
@@ -279,9 +272,9 @@ async def get_unused_derivation_record(self, wallet_id: uint32) -> DerivationRec
279272
# If we have no unused public keys, we will create new ones
280273
unused: Optional[
281274
uint32
282-
] = await self.puzzle_store.get_unused_derivation_path_for_wallet(wallet_id)
275+
] = await self.puzzle_store.get_unused_derivation_path()
283276
if unused is None:
284-
await self.create_more_puzzle_hashes(for_wallet=wallet_id)
277+
await self.create_more_puzzle_hashes()
285278

286279
# Now we must have unused public keys
287280
unused = await self.puzzle_store.get_unused_derivation_path()
@@ -1336,7 +1329,7 @@ async def get_wallet_for_colour(self, colour):
13361329

13371330
async def add_new_wallet(self, wallet: Any, id: int):
13381331
self.wallets[uint32(id)] = wallet
1339-
await self.create_more_puzzle_hashes(for_wallet=id)
1332+
await self.create_more_puzzle_hashes()
13401333

13411334
async def get_coin_records_by_spent(self, spent: bool):
13421335
return await self.wallet_store.get_coin_records_by_spent(spent)

src/wallet/websocket_server.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from src.simulator.simulator_protocol import FarmNewBlockProtocol
2727
from src.util.config import load_config_cli, load_config
2828
from src.util.ints import uint64
29+
from src.types.sized_bytes import bytes32
2930
from src.util.logging import initialize_logging
3031
from src.wallet.util.wallet_types import WalletType
3132
from src.wallet.rl_wallet.rl_wallet import RLWallet
@@ -224,7 +225,7 @@ async def create_new_wallet(self, websocket, request, response_api):
224225
response = {"success": True, "type": cc_wallet.wallet_info.type.name}
225226
return await websocket.send(format_response(response_api, response))
226227
elif request["mode"] == "existing":
227-
cc_wallet: CCWallet = await CCWallet.create_wallet_for_cc(
228+
cc_wallet = await CCWallet.create_wallet_for_cc(
228229
wallet_state_manager, main_wallet, request["colour"]
229230
)
230231
response = {"success": True, "type": cc_wallet.wallet_info.type.name}
@@ -405,7 +406,7 @@ async def cc_get_new_innerpuzzlehash(self, websocket, request, response_api):
405406

406407
wallet_id = int(request["wallet_id"])
407408
wallet: CCWallet = self.wallet_node.wallet_state_manager.wallets[wallet_id]
408-
innerpuz: str = await wallet.get_new_inner_hash()
409+
innerpuz: bytes32 = await wallet.get_new_inner_hash()
409410
response = {"innerpuz": innerpuz.hex()}
410411
return await websocket.send(format_response(response_api, response))
411412

tests/cc_wallet/test_cc_wallet.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ async def test_cc_spend(self, two_wallet_nodes):
133133
await self.time_out_assert(15, cc_wallet.get_confirmed_balance, 100)
134134
await self.time_out_assert(15, cc_wallet.get_unconfirmed_balance, 100)
135135

136+
assert cc_wallet.cc_info.my_core
136137
colour = cc_wallet_puzzles.get_genesis_from_core(cc_wallet.cc_info.my_core)
137138

138139
cc_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(
@@ -232,10 +233,10 @@ async def test_generate_zero_val(self, two_wallet_nodes):
232233
for i in range(1, num_blocks):
233234
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
234235

235-
236236
await self.time_out_assert(15, cc_wallet.get_confirmed_balance, 100)
237237
await self.time_out_assert(15, cc_wallet.get_unconfirmed_balance, 100)
238238

239+
assert cc_wallet.cc_info.my_core
239240
colour = cc_wallet_puzzles.get_genesis_from_core(cc_wallet.cc_info.my_core)
240241

241242
cc_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(
@@ -295,6 +296,7 @@ async def test_cc_trade(self, two_wallet_nodes):
295296
await self.time_out_assert(15, cc_wallet.get_confirmed_balance, 100)
296297
await self.time_out_assert(15, cc_wallet.get_unconfirmed_balance, 100)
297298

299+
assert cc_wallet.cc_info.my_core
298300
colour = cc_wallet_puzzles.get_genesis_from_core(cc_wallet.cc_info.my_core)
299301

300302
cc_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(
@@ -382,6 +384,7 @@ async def test_cc_spend_uncoloured(self, two_wallet_nodes):
382384
await self.time_out_assert(15, cc_wallet.get_confirmed_balance, 100)
383385
await self.time_out_assert(15, cc_wallet.get_unconfirmed_balance, 100)
384386

387+
assert cc_wallet.cc_info.my_core
385388
colour = cc_wallet_puzzles.get_genesis_from_core(cc_wallet.cc_info.my_core)
386389

387390
cc_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(
@@ -396,7 +399,6 @@ async def test_cc_spend_uncoloured(self, two_wallet_nodes):
396399
for i in range(1, num_blocks):
397400
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
398401

399-
400402
await self.time_out_assert(15, cc_wallet.get_confirmed_balance, 40)
401403
await self.time_out_assert(15, cc_wallet.get_unconfirmed_balance, 40)
402404

@@ -412,7 +414,6 @@ async def test_cc_spend_uncoloured(self, two_wallet_nodes):
412414
for i in range(0, num_blocks):
413415
await full_node_1.farm_new_block(FarmNewBlockProtocol(token_bytes()))
414416

415-
416417
id = cc_wallet_2.wallet_info.id
417418
wsm = cc_wallet_2.wallet_state_manager
418419
await self.time_out_assert(15, wsm.get_confirmed_balance_for_wallet, 70, id)
@@ -457,6 +458,7 @@ async def test_cc_trade_with_multiple_colours(self, two_wallet_nodes):
457458
await self.time_out_assert(15, red_wallet.get_confirmed_balance, 100)
458459
await self.time_out_assert(15, red_wallet.get_unconfirmed_balance, 100)
459460

461+
assert red_wallet.cc_info.my_core
460462
red = cc_wallet_puzzles.get_genesis_from_core(red_wallet.cc_info.my_core)
461463

462464
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph2))
@@ -469,6 +471,7 @@ async def test_cc_trade_with_multiple_colours(self, two_wallet_nodes):
469471
for i in range(1, num_blocks):
470472
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
471473

474+
assert blue_wallet_2.cc_info.my_core
472475
blue = cc_wallet_puzzles.get_genesis_from_core(blue_wallet_2.cc_info.my_core)
473476

474477
red_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(
@@ -570,11 +573,10 @@ async def test_create_offer_with_zero_val(self, two_wallet_nodes):
570573
for i in range(1, num_blocks):
571574
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
572575

573-
574576
await self.time_out_assert(15, cc_wallet.get_unconfirmed_balance, 100)
575577
await self.time_out_assert(15, cc_wallet.get_confirmed_balance, 100)
576578

577-
579+
assert cc_wallet.cc_info.my_core
578580
colour = cc_wallet_puzzles.get_genesis_from_core(cc_wallet.cc_info.my_core)
579581

580582
cc_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(
@@ -622,6 +624,5 @@ async def test_create_offer_with_zero_val(self, two_wallet_nodes):
622624
for i in range(0, num_blocks):
623625
await full_node_1.farm_new_block(FarmNewBlockProtocol(token_bytes()))
624626

625-
626627
await self.time_out_assert(15, cc_wallet_2.get_confirmed_balance, 30)
627628
await self.time_out_assert(15, cc_wallet_2.get_confirmed_balance, 30)

0 commit comments

Comments
 (0)