@@ -22,13 +22,13 @@ def perform(local_tip_block = nil)
2222 end
2323 benchmark :recalculate_udt_transactions_count , local_tip_block
2424 benchmark :decrease_records_count , local_tip_block
25+ benchmark :update_address_balance_and_ckb_transactions_count , local_tip_block
2526
2627 ApplicationRecord . benchmark "invalid! block" do
2728 local_tip_block . invalid!
2829 end
2930
3031 benchmark :recalculate_udt_accounts , udt_type_hashes , local_tip_block
31- benchmark :update_address_balance_and_ckb_transactions_count , local_tip_block
3232 benchmark :revert_block_rewards , local_tip_block
3333 ForkedEvent . create! ( block_number : local_tip_block . number , epoch_number : local_tip_block . epoch ,
3434 block_timestamp : local_tip_block . timestamp )
@@ -40,22 +40,76 @@ def perform(local_tip_block = nil)
4040 end
4141
4242 def update_address_balance_and_ckb_transactions_count ( local_tip_block )
43- snapshots = AddressBlockSnapshot . where . not ( block_id : local_tip_block . id ) . where ( address_id : local_tip_block . address_ids ) . order ( block_number : :desc ) . distinct . group_by ( &:address_id )
44- local_tip_block . contained_addresses . each do |address |
45- snapshot = snapshots . fetch ( address . id , [ ] ) . first
46- if snapshot . present?
47- attrs = snapshot . final_state
48- address . update! ( attrs )
49- else
50- address . live_cells_count = address . cell_outputs . live . count
51- address . ckb_transactions_count = AccountBook . tx_committed . where ( address_id : address . id ) . count
52- address . dao_transactions_count = DaoEvent . processed . where ( address_id : address . id ) . distinct . count ( :ckb_transaction_id )
53- address . cal_balance!
54- address . save!
55- end
43+ select_fields = [
44+ "address_id" ,
45+ "COUNT(*) AS cells_count" ,
46+ "SUM(capacity) AS total_capacity" ,
47+ "SUM(CASE WHEN type_hash IS NOT NULL OR data_hash IS NOT NULL THEN capacity ELSE 0 END) AS balance_occupied" ,
48+ ]
49+ output_addrs =
50+ local_tip_block . cell_outputs . live . select ( select_fields . join ( ", " ) ) . group ( :address_id )
51+ input_addrs =
52+ CellOutput . where ( consumed_block_timestamp : local_tip_block . timestamp ) . select ( select_fields . join ( ", " ) ) . group ( :address_id )
53+ out_hash = output_addrs . each_with_object ( { } ) do |row , h |
54+ h [ row . address_id ] = {
55+ cells_count : row . cells_count . to_i ,
56+ total_capacity : row . total_capacity . to_i ,
57+ balance_occupied : row . balance_occupied . to_i ,
58+ }
59+ end
60+
61+ in_hash = input_addrs . each_with_object ( { } ) do |row , h |
62+ h [ row . address_id ] = {
63+ cells_count : row . cells_count . to_i ,
64+ total_capacity : row . total_capacity . to_i ,
65+ balance_occupied : row . balance_occupied . to_i ,
66+ }
5667 end
5768
58- AddressBlockSnapshot . where ( block_id : local_tip_block . id ) . delete_all
69+ # Merge keys
70+ all_ids = in_hash . keys | out_hash . keys
71+
72+ # 计算差值
73+ address_balance_diff = all_ids . each_with_object ( { } ) do |addr_id , h |
74+ input = in_hash [ addr_id ] || { cells_count : 0 , total_capacity : 0 , balance_occupied : 0 }
75+ output = out_hash [ addr_id ] || { cells_count : 0 , total_capacity : 0 , balance_occupied : 0 }
76+
77+ h [ addr_id ] = {
78+ cells_count : input [ :cells_count ] - output [ :cells_count ] ,
79+ total_capacity : input [ :total_capacity ] - output [ :total_capacity ] ,
80+ balance_occupied : input [ :balance_occupied ] - output [ :balance_occupied ] ,
81+ }
82+ end
83+ # Preload dao transaction counts for all addresses in one query
84+ dao_tx_counts = DaoEvent . processed .
85+ where ( block_id : local_tip_block . id , address_id : all_ids ) .
86+ group ( :address_id ) .
87+ distinct .
88+ count ( :ckb_transaction_id )
89+ tx_count_diffs = AccountBook . tx_committed .
90+ where ( block_number : local_tip_block . number , address_id : all_ids ) .
91+ group ( :address_id ) .
92+ count
93+
94+ changes =
95+ address_balance_diff . map do |address_id , changes |
96+ tx_count_diff = tx_count_diffs [ address_id ] || 0
97+ dao_tx_count_diff = dao_tx_counts [ address_id ] || 0
98+ { address_id : address_id } . merge ( changes ) . merge ( { ckb_transactions_count : tx_count_diff , dao_transactions_count : dao_tx_count_diff } )
99+ end
100+
101+ changes . each do |change |
102+ addr = Address . find_by_id ( change [ :address_id ] )
103+ if addr
104+ addr . update! (
105+ live_cells_count : addr . live_cells_count + change [ :cells_count ] ,
106+ ckb_transactions_count : addr . ckb_transactions_count - change [ :ckb_transactions_count ] ,
107+ balance : addr . balance + change [ :total_capacity ] ,
108+ balance_occupied : addr . balance_occupied + change [ :balance_occupied ] ,
109+ dao_transactions_count : addr . dao_transactions_count - change [ :dao_transactions_count ]
110+ )
111+ end
112+ end
59113 end
60114
61115 def recalculate_udt_transactions_count ( local_tip_block )
0 commit comments