diff --git a/app/jobs/revert_block_job.rb b/app/jobs/revert_block_job.rb index 670acbbe1..bd1699505 100644 --- a/app/jobs/revert_block_job.rb +++ b/app/jobs/revert_block_job.rb @@ -21,7 +21,6 @@ def perform(local_tip_block = nil) uniq.concat(local_tip_block.cell_outputs.m_nft_token.pluck(:type_hash).uniq) end benchmark :recalculate_udt_transactions_count, local_tip_block - benchmark :recalculate_dao_contract_transactions_count, local_tip_block benchmark :decrease_records_count, local_tip_block ApplicationRecord.benchmark "invalid! block" do @@ -60,14 +59,6 @@ def update_address_balance_and_ckb_transactions_count(local_tip_block) AddressBlockSnapshot.where(block_id: local_tip_block.id).delete_all end - def recalculate_dao_contract_transactions_count(local_tip_block) - dao_transactions_count = local_tip_block.ckb_transactions.where("tags @> array[?]::varchar[]", ["dao"]).count - if dao_transactions_count > 0 - DaoContract.default_contract.decrement!(:ckb_transactions_count, - dao_transactions_count) - end - end - def recalculate_udt_transactions_count(local_tip_block) udt_ids = local_tip_block.ckb_transactions.map(&:contained_udt_ids).flatten udt_counts = udt_ids.each_with_object(Hash.new(0)) { |udt_id, counts| counts[udt_id] += 1 } @@ -85,15 +76,6 @@ def recalculate_udt_transactions_count(local_tip_block) Udt.upsert_all(udt_counts_value) if udt_counts_value.present? end - def revert_dao_contract_related_operations(local_tip_block) - dao_events = DaoEvent.where(block: local_tip_block).processed - dao_contract = DaoContract.default_contract - revert_withdraw_from_dao(dao_contract, dao_events) - revert_issue_interest(dao_contract, dao_events) - revert_deposit_to_dao(dao_contract, dao_events) - dao_contract.update(depositors_count: DaoEvent.depositor.count) - end - def recalculate_udt_accounts(udt_type_hashes, local_tip_block) return if udt_type_hashes.blank? @@ -122,38 +104,92 @@ def revert_mining_info(local_tip_block) miner_address.decrement!(:mined_blocks_count) end - def revert_issue_interest(dao_contract, dao_events) - issue_interest_dao_events = dao_events.where(event_type: "issue_interest") + def revert_dao_contract_related_operations(local_tip_block) + dao_events = DaoEvent.where(block: local_tip_block).processed + dao_transactions_count = local_tip_block.ckb_transactions.where("tags @> array[?]::varchar[]", ["dao"]).count + dao_contract = DaoContract.default_contract + + withdraw_transactions_count, withdraw_total_deposit = revert_withdraw_from_dao(dao_events) + claimed_compensation = revert_issue_interest(dao_events) + deposit_transactions_count, deposit_total_deposit = revert_deposit_to_dao(dao_events) + + dao_events.update_all(status: "reverted") + dao_contract.update!(deposit_transactions_count: dao_contract.deposit_transactions_count - deposit_transactions_count, + withdraw_transactions_count: dao_contract.withdraw_transactions_count - withdraw_transactions_count, + total_deposit: dao_contract.total_deposit + withdraw_total_deposit - deposit_total_deposit, + claimed_compensation: dao_contract.claimed_compensation - claimed_compensation, + ckb_transactions_count: dao_contract.ckb_transactions_count - dao_transactions_count, + depositors_count: DaoEvent.depositor.count) + end + + def revert_issue_interest(dao_events) + issue_interest_dao_events = dao_events.issue_interest + claimed_compensation = 0 + address_attrs = {} issue_interest_dao_events.each do |event| - dao_contract.decrement!(:claimed_compensation, event.value) + claimed_compensation += event.value + address = event.address - address.decrement!(:interest, event.value) - event.reverted! + address_attrs[address.id] ||= { + id: address.id, + interest: address.interest, + } + address_attrs[address.id][:interest] -= event.value end + upsert_data = address_attrs.values + Address.upsert_all(upsert_data, unique_by: :id) if upsert_data.present? + claimed_compensation end - def revert_withdraw_from_dao(dao_contract, dao_events) - withdraw_from_dao_events = dao_events.where(event_type: "withdraw_from_dao") + def revert_withdraw_from_dao(dao_events) + withdraw_from_dao_events = dao_events.includes(:address).withdraw_from_dao + ids = withdraw_from_dao_events.pluck(:ckb_transaction_id) DaoEvent.processed.where(withdrawn_transaction_id: ids).update_all(withdrawn_transaction_id: nil) + + redundant_total_deposit = 0 + address_attrs = {} withdraw_from_dao_events.each do |event| - dao_contract.decrement!(:withdraw_transactions_count) - dao_contract.increment!(:total_deposit, event.value) + redundant_total_deposit += event.value + address = event.address - address.increment!(:dao_deposit, event.value) - event.reverted! + address_attrs[address.id] ||= { + id: address.id, + dao_deposit: address.dao_deposit, + is_depositor: address.is_depositor, + } + address_attrs[address.id][:dao_deposit] += event.value + address_attrs[address.id][:is_depositor] = true end + + upsert_data = address_attrs.values + Address.upsert_all(upsert_data, unique_by: :id) if upsert_data.present? + + [withdraw_from_dao_events.size, redundant_total_deposit] end - def revert_deposit_to_dao(dao_contract, dao_events) - deposit_to_dao_events = dao_events.where(event_type: "deposit_to_dao") + def revert_deposit_to_dao(dao_events) + deposit_to_dao_events = dao_events.deposit_to_dao + redundant_total_deposit = 0 + address_attrs = {} + deposit_to_dao_events.each do |event| + redundant_total_deposit += event.value + address = event.address - address.decrement!(:dao_deposit, event.value) - dao_contract.decrement!(:total_deposit, event.value) - dao_contract.decrement!(:deposit_transactions_count) - event.reverted! + address_attrs[address.id] ||= { + id: address.id, + dao_deposit: address.dao_deposit, + } + address_attrs[address.id][:dao_deposit] -= event.value end + + upsert_data = address_attrs.values + address_ids = address_attrs.values.map { |hash| hash[:id] } + Address.upsert_all(upsert_data, unique_by: :id) if upsert_data.present? + Address.where(id: address_ids, dao_deposit: 0).update_all(is_depositor: false) + + [deposit_to_dao_events.size, redundant_total_deposit] end def revert_block_rewards(local_tip_block) diff --git a/app/models/ckb_sync/new_node_data_processor.rb b/app/models/ckb_sync/new_node_data_processor.rb index 28d019e4f..ae2134539 100644 --- a/app/models/ckb_sync/new_node_data_processor.rb +++ b/app/models/ckb_sync/new_node_data_processor.rb @@ -316,9 +316,10 @@ def process_deposit_dao_events!(local_block, dao_contract) addresses_deposit_info[address.id] = { dao_deposit: address.dao_deposit.to_i + dao_output.capacity, - is_depositor: true, + } end + addresses_deposit_info[address.id][:is_depositor] = true deposit_amount += dao_output.capacity deposit_transaction_ids << dao_output.ckb_transaction_id dao_events_attributes << { @@ -351,6 +352,7 @@ def update_addresses_dao_info(addrs_deposit_info) id: address_id, dao_deposit: address_info[:dao_deposit], interest: address_info[:interest], + is_depositor: address_info[:is_depositor], } end Address.upsert_all(addresses_deposit_attributes, record_timestamps: true) if addresses_deposit_attributes.present? diff --git a/test/controllers/api/v1/daily_statistics_controller_test.rb b/test/controllers/api/v1/daily_statistics_controller_test.rb index 5599612c7..40ef5b07c 100644 --- a/test/controllers/api/v1/daily_statistics_controller_test.rb +++ b/test/controllers/api/v1/daily_statistics_controller_test.rb @@ -94,29 +94,6 @@ class DailyStatisticsControllerTest < ActionDispatch::IntegrationTest assert_equal response_json, response.body end - test "should return recent year transactions count and timestamp" do - target_date = Time.current.beginning_of_year - - i = 1 - o_date = i.days.ago - while o_date > target_date - newly_created_object = create(:daily_statistic, created_at_unixtimestamp: o_date) - i += 1 - o_date = i.days.ago - end - daily_statistic_data = DailyStatistic.order(:created_at_unixtimestamp). - where("created_at_unixtimestamp > ?", target_date.to_i). - valid_indicators - valid_get api_v1_daily_statistic_url("transactions_count") - - assert_equal [%w(transactions_count created_at_unixtimestamp).sort], json.dig("data").map { |item| - item.dig("attributes").keys.sort - }.uniq - assert_equal DailyStatisticSerializer.new(daily_statistic_data, params: { indicator: "transactions_count" }).serialized_json, - response.body - assert_equal ((Time.current - target_date) / (24 * 60 * 60)).to_i, json.dig("data").size - end - test "should return recent all days average hash rate" do 100.times do |i| create(:daily_statistic, created_at_unixtimestamp: (360 - i).days.ago.to_i) diff --git a/test/models/ckb_sync/dao_events_test.rb b/test/models/ckb_sync/dao_events_test.rb index 70b92afc3..185477dcf 100644 --- a/test/models/ckb_sync/dao_events_test.rb +++ b/test/models/ckb_sync/dao_events_test.rb @@ -300,8 +300,8 @@ class DaoEventsTest < ActiveSupport::TestCase node_data_processor.call end - deposit_to_dao_events = local_block.dao_events.where(event_type: "withdraw_from_dao") - assert_equal ["reverted"], deposit_to_dao_events.pluck(:status).uniq + dao_events = local_block.dao_events.where(event_type: "withdraw_from_dao") + assert_equal ["reverted"], dao_events.pluck(:status).uniq end end @@ -366,13 +366,15 @@ class DaoEventsTest < ActiveSupport::TestCase node_block = fake_node_block("0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") create(:block, :with_block_hash, number: node_block.header.number - 1) VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do - fake_dao_withdraw_transaction(node_block) + tx = fake_dao_withdraw_transaction(node_block) + assert_equal true, tx.cell_outputs.first.address.is_depositor DaoContract.default_contract.update(total_deposit: 100000000000) assert_difference -> { DaoEvent.where(event_type: "withdraw_from_dao").count }, 1 do node_data_processor.process_block(node_block) end deposit_to_dao_events = Block.find_by(number: node_block.header.number).dao_events.where(event_type: "withdraw_from_dao") + assert_equal false, tx.cell_outputs.first.address.is_depositor assert_equal ["processed"], deposit_to_dao_events.pluck(:status).uniq assert_equal(%w(block_id ckb_transaction_id address_id contract_id event_type value status block_timestamp withdrawn_transaction_id cell_index), deposit_to_dao_events.first.attribute_names.reject do |attribute| attribute.in?(%w(created_at updated_at id)) @@ -540,6 +542,7 @@ class DaoEventsTest < ActiveSupport::TestCase tx = fake_dao_deposit_transaction(node_block) output = tx.outputs.first address = Address.find_or_create_address(output.lock, node_block.header.timestamp) + assert_equal false, address.is_depositor assert_difference -> { address.reload.dao_deposit }, 10**8 * 1000 do node_data_processor.process_block(node_block) @@ -547,6 +550,7 @@ class DaoEventsTest < ActiveSupport::TestCase deposit_to_dao_events = Block.find_by(number: node_block.header.number).dao_events.where(event_type: "deposit_to_dao") assert_equal ["processed"], deposit_to_dao_events.pluck(:status).uniq + assert_equal true, address.reload.is_depositor end end @@ -820,7 +824,7 @@ def fake_dao_withdraw_transaction(node_block) tx_hash: "0x598315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block:, capacity: 10**8 * 1000, lock_script_id: lock.id) - cell_output1.address.update(balance: 10**8 * 1000, dao_deposit: 10**8 * 1000) + cell_output1.address.update(balance: 10**8 * 1000, dao_deposit: 10**8 * 1000, is_depositor: true) cell_output2.address.update(balance: 10**8 * 1000) tx = node_block.transactions.last output = tx.outputs.first diff --git a/test/models/ckb_sync/node_data_processor_test.rb b/test/models/ckb_sync/node_data_processor_test.rb index 0d8f15b81..8785a1d5b 100644 --- a/test/models/ckb_sync/node_data_processor_test.rb +++ b/test/models/ckb_sync/node_data_processor_test.rb @@ -2624,11 +2624,12 @@ class NodeDataProcessorTest < ActiveSupport::TestCase transactions:, header:) block = node_data_processor.process_block(node_block) CkbSync::Api.any_instance.stubs(:get_tip_block_number).returns(block.number + 1) + DaoContract.default_contract.update(deposit_transactions_count: 4) VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", record: :new_episodes) do assert_changes -> { - DaoContract.default_contract.ckb_transactions_count + DaoContract.default_contract.reload.ckb_transactions_count }, from: 2, to: 0 do node_data_processor.call end