@@ -155,9 +155,6 @@ def __init__(
155
155
# faster.
156
156
self .max_additions_per_transaction = pool_config ["max_additions_per_transaction" ]
157
157
158
- # This is the list of payments that we have not sent yet, to farmers
159
- self .pending_payments : Optional [asyncio .Queue ] = None
160
-
161
158
# Keeps track of the latest state of our node
162
159
self .blockchain_state = {"peak" : None }
163
160
@@ -207,8 +204,6 @@ async def start(self):
207
204
self .submit_payment_loop_task = asyncio .create_task (self .submit_payment_loop ())
208
205
self .get_peak_loop_task = asyncio .create_task (self .get_peak_loop ())
209
206
210
- self .pending_payments = asyncio .Queue ()
211
-
212
207
async def stop (self ):
213
208
if self .confirm_partials_loop_task is not None :
214
209
self .confirm_partials_loop_task .cancel ()
@@ -362,8 +357,8 @@ async def create_payment_loop(self):
362
357
await asyncio .sleep (60 )
363
358
continue
364
359
365
- if self .pending_payments . qsize ( ) != 0 :
366
- self .log .warning (f"Pending payments ({ self . pending_payments . qsize () } ), waiting" )
360
+ if ( pending_payment_count := await self .store . get_pending_payment_count () ) != 0 :
361
+ self .log .warning (f"Pending payments ({ pending_payment_count } ), waiting" )
367
362
await asyncio .sleep (60 )
368
363
continue
369
364
@@ -391,34 +386,46 @@ async def create_payment_loop(self):
391
386
self .log .info (f"Total amount to distribute: { amount_to_distribute / (10 ** 12 )} " )
392
387
393
388
async with self .store .lock :
394
- # Get the points of each farmer, as well as payout instructions. Here a chia address is used,
395
- # but other blockchain addresses can also be used.
396
- points_and_ph : List [
397
- Tuple [uint64 , bytes ]
398
- ] = await self .store .get_farmer_points_and_payout_instructions ()
399
- total_points = sum ([pt for (pt , ph ) in points_and_ph ])
389
+ # Get the launcher_id and points of each farmer, as well as payout instructions.
390
+ # Here a chia address is used, but other blockchain addresses can also be used.
391
+ launcher_id_and_points_and_ph : List [
392
+ Tuple [bytes32 , uint64 , bytes32 ]
393
+ ] = await self .store .get_farmer_launcher_id_and_points_and_payout_instructions ()
394
+ total_points = sum ([pt for (launcher_id , pt , ph ) in launcher_id_and_points_and_ph ])
400
395
if total_points > 0 :
401
396
mojo_per_point = floor (amount_to_distribute / total_points )
402
397
self .log .info (f"Paying out { mojo_per_point } mojo / point" )
403
398
399
+ # Pool fee payment record launcher_id is equal to puzzle_hash, points is equal to 0.
404
400
additions_sub_list : List [Dict ] = [
405
- {"puzzle_hash" : self .pool_fee_puzzle_hash , "amount" : pool_coin_amount }
401
+ {
402
+ "launcher_id" : self .pool_fee_puzzle_hash ,
403
+ "puzzle_hash" : self .pool_fee_puzzle_hash ,
404
+ "amount" : pool_coin_amount ,
405
+ "points" : 0 ,
406
+ }
406
407
]
407
- for points , ph in points_and_ph :
408
+ for launcher_id , points , ph in launcher_id_and_points_and_ph :
408
409
if points > 0 :
409
- additions_sub_list .append ({"puzzle_hash" : ph , "amount" : points * mojo_per_point })
410
-
411
- if len (additions_sub_list ) == self .max_additions_per_transaction :
412
- await self .pending_payments .put (additions_sub_list .copy ())
413
- self .log .info (f"Will make payments: { additions_sub_list } " )
414
- additions_sub_list = []
410
+ additions_sub_list .append ({
411
+ "launcher_id" : launcher_id ,
412
+ "puzzle_hash" : ph ,
413
+ "amount" : points * mojo_per_point ,
414
+ "points" : points ,
415
+ })
416
+
417
+ for payment in additions_sub_list :
418
+ await self .store .add_payment (
419
+ payment ["launcher_id" ],
420
+ payment ["puzzle_hash" ],
421
+ uint64 (payment ["amount" ]),
422
+ payment ["points" ],
423
+ uint64 (int (time .time ())),
424
+ False ,
425
+ )
415
426
416
427
if len (additions_sub_list ) > 0 :
417
428
self .log .info (f"Will make payments: { additions_sub_list } " )
418
- await self .pending_payments .put (additions_sub_list .copy ())
419
-
420
- # Subtract the points from each farmer
421
- await self .store .clear_farmer_points ()
422
429
else :
423
430
self .log .info (f"No points for any farmer. Waiting { self .payment_interval } " )
424
431
@@ -441,10 +448,20 @@ async def submit_payment_loop(self):
441
448
await asyncio .sleep (60 )
442
449
continue
443
450
444
- payment_targets = await self .pending_payments .get ()
445
- assert len (payment_targets ) > 0
451
+ pending_payments = await self .store .get_pending_payment_records (self .max_additions_per_transaction )
452
+ if len (pending_payments ) == 0 :
453
+ self .log .info ("No funds to pending payment records" )
454
+ await asyncio .sleep (60 )
455
+ continue
456
+ self .log .info (f"Submitting a payment: { pending_payments } " )
446
457
447
- self .log .info (f"Submitting a payment: { payment_targets } " )
458
+ payment_targets : List [Dict ] = [
459
+ {
460
+ "puzzle_hash" : puzzle_hash ,
461
+ "amount" : amount ,
462
+ }
463
+ for _ , puzzle_hash , amount , _ , _ , _ in pending_payments
464
+ ]
448
465
449
466
# TODO(pool): make sure you have enough to pay the blockchain fee, this will be taken out of the pool
450
467
# fee itself. Alternatively you can set it to 0 and wait longer
@@ -457,34 +474,40 @@ async def submit_payment_loop(self):
457
474
except ValueError as e :
458
475
self .log .error (f"Error making payment: { e } " )
459
476
await asyncio .sleep (10 )
460
- await self .pending_payments .put (payment_targets )
461
477
continue
462
478
463
479
self .log .info (f"Transaction: { transaction } " )
464
480
465
- while (
466
- not transaction . confirmed
467
- or not ( peak_height - transaction . confirmed_at_height ) > self . confirmation_security_threshold
468
- ):
469
- transaction = await self . wallet_rpc_client . get_transaction ( self . wallet_id , transaction . name )
470
- peak_height = self . blockchain_state [ "peak" ]. height
471
- self . log . info (
472
- f"Waiting for transaction to obtain { self . confirmation_security_threshold } confirmations"
481
+ async with self . store . tx ():
482
+ await self . store . update_is_payment (
483
+ [
484
+ ( launcher_id , points , timestamp )
485
+ for launcher_id , _ , _ , points , timestamp , _ in pending_payments
486
+ ],
487
+ is_payment = True ,
488
+ auto_commit = False ,
473
489
)
474
- if not transaction .confirmed :
475
- self .log .info (f"Not confirmed. In mempool? { transaction .is_in_mempool ()} " )
476
- else :
477
- self .log .info (f"Confirmations: { peak_height - transaction .confirmed_at_height } " )
478
- await asyncio .sleep (10 )
479
490
480
- # TODO(pool): persist in DB
481
- self .log .info (f"Successfully confirmed payments { payment_targets } " )
491
+ while (
492
+ not transaction .confirmed
493
+ or not (peak_height - transaction .confirmed_at_height ) > self .confirmation_security_threshold
494
+ ):
495
+ transaction = await self .wallet_rpc_client .get_transaction (self .wallet_id , transaction .name )
496
+ peak_height = self .blockchain_state ["peak" ].height
497
+ self .log .info (
498
+ f"Waiting for transaction to obtain { self .confirmation_security_threshold } confirmations"
499
+ )
500
+ if not transaction .confirmed :
501
+ self .log .info (f"Not confirmed. In mempool? { transaction .is_in_mempool ()} " )
502
+ else :
503
+ self .log .info (f"Confirmations: { peak_height - transaction .confirmed_at_height } " )
504
+ await asyncio .sleep (10 )
482
505
506
+ self .log .info (f"Successfully confirmed payments { pending_payments } " )
483
507
except asyncio .CancelledError :
484
508
self .log .info ("Cancelled submit_payment_loop, closing" )
485
509
return
486
510
except Exception as e :
487
- # TODO(pool): retry transaction if failed
488
511
self .log .error (f"Unexpected error in submit_payment_loop: { e } " )
489
512
await asyncio .sleep (60 )
490
513
0 commit comments