From 57ef81676b832539f97e1ba288ed8362ec44e418 Mon Sep 17 00:00:00 2001 From: Miles Zhang Date: Thu, 2 Jan 2025 10:59:51 +0900 Subject: [PATCH] feat: refactor dao_event (#2378) * feat: use DaoEvent replace AddressDaoTransaction Signed-off-by: Miles Zhang * refactor: dao_event Signed-off-by: Miles Zhang * test: fix test Signed-off-by: Miles Zhang * fix: typo Signed-off-by: Miles Zhang * refactor: revert job of dao contract Signed-off-by: Miles Zhang * feat: use task check dao event not missed Signed-off-by: Miles Zhang --------- Signed-off-by: Miles Zhang --- .../v1/address_dao_transactions_controller.rb | 4 +- .../v1/address_udt_transactions_controller.rb | 8 +- app/jobs/revert_block_job.rb | 124 +++++------ app/models/address.rb | 3 +- app/models/address_dao_transaction.rb | 16 -- .../ckb_sync/new_node_data_processor.rb | 153 ++++---------- app/models/ckb_transaction.rb | 4 +- app/models/daily_statistic.rb | 47 ++--- app/models/dao_contract.rb | 5 +- app/models/dao_event.rb | 36 +--- .../charts/daily_statistic_generator.rb | 6 +- ...23023654_remove_address_dao_transaction.rb | 5 + ...231022644_add_unique_index_to_dao_event.rb | 5 + db/structure.sql | 35 +--- lib/tasks/migration/check_dao_event.rake | 36 ++++ .../fill_cell_index_to_dao_event.rake | 50 +++-- .../contract_transactions_controller_test.rb | 3 +- .../v1/daily_statistics_controller_test.rb | 23 --- test/factories/ckb_transaction.rb | 3 - test/factories/lock_script.rb | 3 + test/models/address_test.rb | 11 +- test/models/ckb_sync/dao_events_test.rb | 192 ++---------------- .../ckb_sync/node_data_processor_test.rb | 16 +- test/models/dao_contract_test.rb | 3 - .../charts/daily_statistic_generator_test.rb | 43 ---- test/test_helper.rb | 4 +- 26 files changed, 271 insertions(+), 567 deletions(-) delete mode 100644 app/models/address_dao_transaction.rb create mode 100644 db/migrate/20241223023654_remove_address_dao_transaction.rb create mode 100644 db/migrate/20241231022644_add_unique_index_to_dao_event.rb create mode 100644 lib/tasks/migration/check_dao_event.rake diff --git a/app/controllers/api/v1/address_dao_transactions_controller.rb b/app/controllers/api/v1/address_dao_transactions_controller.rb index 215d6a506..0f77d18d6 100644 --- a/app/controllers/api/v1/address_dao_transactions_controller.rb +++ b/app/controllers/api/v1/address_dao_transactions_controller.rb @@ -8,8 +8,8 @@ def show address = Address.find_address!(params[:id]) raise Api::V1::Exceptions::AddressNotFoundError if address.is_a?(NullAddress) - ckb_dao_transactions = address.ckb_dao_transactions.select(:id, :tx_hash, :block_id, :block_number, :tags, :block_timestamp, :is_cellbase, :updated_at, :created_at). - recent.page(@page).per(@page_size).fast_page + ckb_dao_transactions = address.ckb_dao_transactions.select(:id, :tx_hash, :block_id, :block_number, :tags, :block_timestamp, :is_cellbase, :updated_at, :created_at, :tx_index). + recent.page(@page).per(@page_size) json = Rails.cache.realize(ckb_dao_transactions.cache_key, version: ckb_dao_transactions.cache_version) do records_counter = RecordCounters::AddressDaoTransactions.new(address) diff --git a/app/controllers/api/v1/address_udt_transactions_controller.rb b/app/controllers/api/v1/address_udt_transactions_controller.rb index b4aec1fcb..f725999f4 100644 --- a/app/controllers/api/v1/address_udt_transactions_controller.rb +++ b/app/controllers/api/v1/address_udt_transactions_controller.rb @@ -12,14 +12,14 @@ def show udt = Udt.find_by(type_hash: params[:type_hash], published: true) raise Api::V1::Exceptions::UdtNotFoundError if udt.blank? - ckb_dao_transactions = address.ckb_udt_transactions(udt.id). + ckb_udt_transactions = address.ckb_udt_transactions(udt.id). select(:id, :tx_hash, :block_id, :block_number, :block_timestamp, :is_cellbase, :updated_at, :created_at, :tags). recent.page(@page).per(@page_size).fast_page json = - Rails.cache.realize(ckb_dao_transactions.cache_key, version: ckb_dao_transactions.cache_version) do + Rails.cache.realize(ckb_udt_transactions.cache_key, version: ckb_udt_transactions.cache_version) do records_counter = RecordCounters::AddressUdtTransactions.new(address, udt.id) - options = FastJsonapi::PaginationMetaGenerator.new(request:, records: ckb_dao_transactions, page: @page, page_size: @page_size, records_counter:).call - CkbTransactionsSerializer.new(ckb_dao_transactions, options.merge(params: { previews: true })).serialized_json + options = FastJsonapi::PaginationMetaGenerator.new(request:, records: ckb_udt_transactions, page: @page, page_size: @page_size, records_counter:).call + CkbTransactionsSerializer.new(ckb_udt_transactions, options.merge(params: { previews: true })).serialized_json end render json: diff --git a/app/jobs/revert_block_job.rb b/app/jobs/revert_block_job.rb index 54e3de4ab..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 @@ -51,7 +50,7 @@ def update_address_balance_and_ckb_transactions_count(local_tip_block) address.live_cells_count = address.cell_outputs.live.count # address.ckb_transactions_count = address.custom_ckb_transactions.count address.ckb_transactions_count = AccountBook.where(address_id: address.id).count - address.dao_transactions_count = AddressDaoTransaction.where(address_id: address.id).count + address.dao_transactions_count = DaoEvent.processed.where(address_id: address.id).distinct(:ckb_transaction_id).count address.cal_balance! address.save! end @@ -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,16 +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) - revert_new_dao_depositor(dao_contract, dao_events) - revert_take_away_all_deposit(dao_contract, dao_events) - end - def recalculate_udt_accounts(udt_type_hashes, local_tip_block) return if udt_type_hashes.blank? @@ -125,61 +106,90 @@ def revert_mining_info(local_tip_block) 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 - revert_withdraw_from_dao(dao_contract, dao_events) - revert_issue_interest(dao_contract, dao_events) - revert_deposit_to_dao(dao_contract, dao_events) - revert_new_dao_depositor(dao_contract, dao_events) - revert_take_away_all_deposit(dao_contract, dao_events) - end - def revert_take_away_all_deposit(dao_contract, dao_events) - take_away_all_deposit_dao_events = dao_events.where(event_type: "take_away_all_deposit") - take_away_all_deposit_dao_events.each do |event| - dao_contract.increment!(:depositors_count) - event.reverted! - end + 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_contract, dao_events) - issue_interest_dao_events = dao_events.where(event_type: "issue_interest") + 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 - end - def revert_new_dao_depositor(dao_contract, dao_events) - new_dao_depositor_events = dao_events.where(event_type: "new_dao_depositor") - new_dao_depositor_events.each do |event| - dao_contract.decrement!(:depositors_count) - dao_contract.decrement!(:total_depositors_count) - event.reverted! - 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/address.rb b/app/models/address.rb index 4381be719..4408712ce 100644 --- a/app/models/address.rb +++ b/app/models/address.rb @@ -13,6 +13,7 @@ class Address < ApplicationRecord has_many :udt_accounts has_many :dao_events belongs_to :lock_script, optional: true + has_many :ckb_dao_transactions, -> { distinct }, through: :dao_events, source: :ckb_transaction has_one :bitcoin_address_mapping, foreign_key: "ckb_address_id" has_one :bitcoin_address, through: :bitcoin_address_mapping @@ -33,8 +34,6 @@ def custom_ckb_transactions ckb_transactions end - has_and_belongs_to_many :ckb_dao_transactions, class_name: "CkbTransaction", join_table: "address_dao_transactions" - def ckb_udt_transactions(udt) udt = Udt.find_by_id(udt) unless udt.is_a?(Udt) udt&.ckb_transactions || [] diff --git a/app/models/address_dao_transaction.rb b/app/models/address_dao_transaction.rb deleted file mode 100644 index 5800b7dee..000000000 --- a/app/models/address_dao_transaction.rb +++ /dev/null @@ -1,16 +0,0 @@ -# save the relationship of dao transactions in address -class AddressDaoTransaction < ApplicationRecord -end - -# == Schema Information -# -# Table name: address_dao_transactions -# -# ckb_transaction_id :bigint -# address_id :bigint -# -# Indexes -# -# address_dao_tx_alt_pk (address_id,ckb_transaction_id) UNIQUE -# index_address_dao_transactions_on_ckb_transaction_id (ckb_transaction_id) -# diff --git a/app/models/ckb_sync/new_node_data_processor.rb b/app/models/ckb_sync/new_node_data_processor.rb index 7e27c55de..ae2134539 100644 --- a/app/models/ckb_sync/new_node_data_processor.rb +++ b/app/models/ckb_sync/new_node_data_processor.rb @@ -10,7 +10,7 @@ class NewNodeDataProcessor value :reorg_started_at, global: true attr_accessor :local_tip_block, :pending_raw_block, :ckb_txs, :target_block, :addrs_changes, :outputs, :inputs, :outputs_data, :udt_address_ids, :contained_address_ids, - :dao_address_ids, :contained_udt_ids, :cell_datas, :enable_cota, :token_transfer_ckb_tx_ids + :contained_udt_ids, :cell_datas, :enable_cota, :token_transfer_ckb_tx_ids def initialize(enable_cota = ENV["COTA_AGGREGATOR_URL"].present?) @enable_cota = enable_cota @@ -65,21 +65,20 @@ def process_block(node_block, refresh_balance: true) tags = [] @udt_address_ids = udt_address_ids = [] - @dao_address_ids = dao_address_ids = [] @contained_udt_ids = contained_udt_ids = [] @contained_address_ids = contained_address_ids = [] @token_transfer_ckb_tx_ids = token_transfer_ckb_tx_ids = Set.new benchmark :process_ckb_txs, node_block, ckb_txs, contained_address_ids, - contained_udt_ids, dao_address_ids, tags, udt_address_ids + contained_udt_ids, tags, udt_address_ids addrs_changes = Hash.new { |hash, key| hash[key] = {} } input_capacities, output_capacities = benchmark :build_cells_and_locks!, local_block, node_block, ckb_txs, inputs, outputs, - tags, udt_address_ids, dao_address_ids, contained_udt_ids, contained_address_ids, addrs_changes, token_transfer_ckb_tx_ids, cell_deps + tags, udt_address_ids, contained_udt_ids, contained_address_ids, addrs_changes, token_transfer_ckb_tx_ids, cell_deps # update explorer data benchmark :update_ckb_txs_rel_and_fee, ckb_txs, tags, input_capacities, output_capacities, udt_address_ids, - dao_address_ids, contained_udt_ids, contained_address_ids + contained_udt_ids, contained_address_ids benchmark :update_block_info!, local_block benchmark :update_block_reward_info!, local_block benchmark :update_mining_info, local_block @@ -142,15 +141,13 @@ def async_update_udt_infos(local_block) end def process_ckb_txs( - node_block, ckb_txs, contained_address_ids, contained_udt_ids, dao_address_ids, tags, -udt_address_ids + node_block, ckb_txs, contained_address_ids, contained_udt_ids, tags, udt_address_ids ) tx_index = 0 ckb_txs.each do |cbk_tx| cbk_tx["tx_hash"][0] = "0" tags[tx_index] = Set.new udt_address_ids[tx_index] = Set.new - dao_address_ids[tx_index] = Set.new contained_udt_ids[tx_index] = Set.new contained_address_ids[tx_index] = Set.new tx_index += 1 @@ -178,12 +175,11 @@ def increase_records_count(local_block) def process_dao_events!(local_tip_block = @local_tip_block) local_block = local_tip_block - new_dao_depositors = {} dao_contract = DaoContract.default_contract - process_deposit_dao_events!(local_block, new_dao_depositors, dao_contract) - process_withdraw_dao_events!(local_block, new_dao_depositors, dao_contract) + process_deposit_dao_events!(local_block, dao_contract) + process_withdraw_dao_events!(local_block, dao_contract) process_interest_dao_events!(local_block, dao_contract) - build_new_dao_depositor_events!(local_block, new_dao_depositors, dao_contract) + dao_contract.update(depositors_count: DaoEvent.depositor.count) # update dao contract ckb_transactions_count dao_contract.increment!(:ckb_transactions_count, @@ -192,51 +188,27 @@ def process_dao_events!(local_tip_block = @local_tip_block) ).count) end - def build_new_dao_depositor_events!(local_block, new_dao_depositors, dao_contract) - new_dao_events_attributes = [] - new_dao_depositors.each do |address_id, ckb_transaction_id| - new_dao_events_attributes << { - block_id: local_block.id, ckb_transaction_id:, address_id:, event_type: "new_dao_depositor", - value: 1, status: "processed", contract_id: dao_contract.id, block_timestamp: local_block.timestamp, - created_at: Time.current, updated_at: Time.current - } - end - - if new_dao_events_attributes.present? - DaoEvent.insert_all!(new_dao_events_attributes) - dao_contract.update!( - total_depositors_count: dao_contract.total_depositors_count + new_dao_events_attributes.size, - depositors_count: dao_contract.depositors_count + new_dao_events_attributes.size, - ) - address_ids = [] - new_dao_events_attributes.each do |dao_event_attr| - address_ids << dao_event_attr[:address_id] - end - Address.where(id: address_ids).update_all(is_depositor: true) - end - end - # Process DAO withdraw # Warning:because DAO withdraw is also a cell, to the destination address of withdraw is the address of the withdraw cell output. # So it's possible that the deposit address is different with the withdraw address. - def process_withdraw_dao_events!(local_block, _new_dao_depositors, -dao_contract) + def process_withdraw_dao_events!(local_block, dao_contract) dao_contract = DaoContract.default_contract withdraw_amount = 0 withdraw_transaction_ids = Set.new addrs_withdraw_info = {} - claimed_compensation = 0 - take_away_all_deposit_count = 0 + # When DAO Deposit Cell appears in cell inputs, the transaction is DAO withdrawal local_block.cell_inputs.nervos_dao_deposit.select(:id, :ckb_transaction_id, :previous_cell_output_id, :index).find_in_batches do |dao_inputs| dao_events_attributes = [] + updated_deposit_dao_events_attributes = [] dao_inputs.each do |dao_input| previous_cell_output = CellOutput. where(id: dao_input.previous_cell_output_id). - select(:address_id, :ckb_transaction_id, :dao, :cell_index, :capacity, :occupied_capacity). + select(:address_id, :ckb_transaction_id, :block_id, :dao, :cell_index, :capacity, :occupied_capacity). take! + address = previous_cell_output.address address.dao_deposit ||= 0 if addrs_withdraw_info.key?(address.id) @@ -244,13 +216,14 @@ def process_withdraw_dao_events!(local_block, _new_dao_depositors, else addrs_withdraw_info[address.id] = { dao_deposit: address.dao_deposit.to_i - previous_cell_output.capacity, - is_depositor: address.is_depositor, - created_at: address.created_at, } end - if addrs_withdraw_info[address.id][:dao_deposit] < 0 - addrs_withdraw_info[address.id][:dao_deposit] = 0 + if addrs_withdraw_info[address.id][:dao_deposit] == 0 + addrs_withdraw_info[address.id][:is_depositor] = false end + + updated_deposit_dao_events_attributes << { block_id: previous_cell_output.block_id, ckb_transaction_id: previous_cell_output.ckb_transaction_id, cell_index: dao_input.index, event_type: "deposit_to_dao", + withdrawn_transaction_id: dao_input.ckb_transaction_id } dao_events_attributes << { ckb_transaction_id: dao_input.ckb_transaction_id, cell_index: dao_input.index, @@ -260,40 +233,22 @@ def process_withdraw_dao_events!(local_block, _new_dao_depositors, event_type: "withdraw_from_dao", value: previous_cell_output.capacity, status: "processed", - contract_id: dao_contract.id, created_at: Time.current, - updated_at: Time.current + contract_id: dao_contract.id, } - address_dao_deposit = Address.where(id: previous_cell_output.address_id).pick(:dao_deposit) - if address_dao_deposit && (address_dao_deposit - previous_cell_output.capacity).zero? - take_away_all_deposit_count += 1 - addrs_withdraw_info[address.id][:is_depositor] = false - dao_events_attributes << { - ckb_transaction_id: dao_input.ckb_transaction_id, - cell_index: nil, - block_id: local_block.id, - block_timestamp: local_block.timestamp, - address_id: previous_cell_output.address_id, - event_type: "take_away_all_deposit", - value: 1, - status: "processed", - contract_id: dao_contract.id, - created_at: Time.current, - updated_at: Time.current, - } - else - puts "Cannot find address dao for #{previous_cell_output.address_id}" - end withdraw_amount += previous_cell_output.capacity withdraw_transaction_ids << dao_input.ckb_transaction_id end - DaoEvent.insert_all!(dao_events_attributes) if dao_events_attributes.present? + DaoEvent.upsert_all(dao_events_attributes, unique_by: %i[block_id ckb_transaction_id cell_index event_type]) if dao_events_attributes.present? + if updated_deposit_dao_events_attributes.present? + DaoEvent.upsert_all(updated_deposit_dao_events_attributes, unique_by: %i[block_id ckb_transaction_id cell_index event_type], + update_only: :withdrawn_transaction_id) + end end # update dao contract info dao_contract.update!( total_deposit: dao_contract.total_deposit - withdraw_amount, withdraw_transactions_count: dao_contract.withdraw_transactions_count + withdraw_transaction_ids.size, - depositors_count: dao_contract.depositors_count - take_away_all_deposit_count, ) update_addresses_dao_info(addrs_withdraw_info) end @@ -304,8 +259,8 @@ def process_withdraw_dao_events!(local_block, _new_dao_depositors, def process_interest_dao_events!(local_block, dao_contract) addrs_withdraw_info = {} claimed_compensation = 0 - local_block.cell_inputs.nervos_dao_withdrawing.select(:id, :ckb_transaction_id, :block_id, - :previous_cell_output_id, :index).find_in_batches do |dao_inputs| + local_block.cell_inputs.nervos_dao_withdrawing.select(:id, :ckb_transaction_id, :block_id, :index, + :previous_cell_output_id).find_in_batches do |dao_inputs| dao_events_attributes = [] dao_inputs.each do |dao_input| previous_cell_output = CellOutput. @@ -319,8 +274,6 @@ def process_interest_dao_events!(local_block, dao_contract) else addrs_withdraw_info[address.id] = { interest: address.interest.to_i + interest, - is_depositor: address.is_depositor, - created_at: address.created_at, } end # addrs_withdraw_info[address.id][:dao_deposit] = 0 if addrs_withdraw_info[address.id][:dao_deposit] < 0 @@ -334,12 +287,10 @@ def process_interest_dao_events!(local_block, dao_contract) value: interest, status: "processed", contract_id: dao_contract.id, - created_at: Time.current, - updated_at: Time.current, } claimed_compensation += interest end - DaoEvent.insert_all!(dao_events_attributes) if dao_events_attributes.present? + DaoEvent.upsert_all(dao_events_attributes, unique_by: %i[block_id ckb_transaction_id cell_index event_type]) if dao_events_attributes.present? end # update dao contract info dao_contract.update!( @@ -348,14 +299,14 @@ def process_interest_dao_events!(local_block, dao_contract) update_addresses_dao_info(addrs_withdraw_info) end - def process_deposit_dao_events!(local_block, new_dao_depositors, dao_contract) + def process_deposit_dao_events!(local_block, dao_contract) deposit_amount = 0 deposit_transaction_ids = Set.new addresses_deposit_info = {} # build deposit dao events local_block.cell_outputs.nervos_dao_deposit.select(:id, :address_id, :capacity, :ckb_transaction_id, :cell_index).find_in_batches do |dao_outputs| - deposit_dao_events_attributes = [] + dao_events_attributes = [] dao_outputs.each do |dao_output| address = dao_output.address address.dao_deposit ||= 0 @@ -365,17 +316,13 @@ def process_deposit_dao_events!(local_block, new_dao_depositors, dao_contract) addresses_deposit_info[address.id] = { dao_deposit: address.dao_deposit.to_i + dao_output.capacity, - interest: address.interest, - is_depositor: address.is_depositor, - created_at: address.created_at, + } end - if address.dao_deposit.zero? && !new_dao_depositors.key?(address.id) - new_dao_depositors[address.id] = dao_output.ckb_transaction_id - end + addresses_deposit_info[address.id][:is_depositor] = true deposit_amount += dao_output.capacity deposit_transaction_ids << dao_output.ckb_transaction_id - deposit_dao_events_attributes << { + dao_events_attributes << { ckb_transaction_id: dao_output.ckb_transaction_id, cell_index: dao_output.cell_index, block_id: local_block.id, @@ -385,17 +332,16 @@ def process_deposit_dao_events!(local_block, new_dao_depositors, dao_contract) status: "processed", contract_id: dao_contract.id, block_timestamp: local_block.timestamp, - created_at: Time.current, - updated_at: Time.current, } end - DaoEvent.insert_all!(deposit_dao_events_attributes) if deposit_dao_events_attributes.present? + DaoEvent.upsert_all(dao_events_attributes, unique_by: %i[block_id ckb_transaction_id cell_index event_type]) if dao_events_attributes.present? end # update dao contract info dao_contract.update!( total_deposit: dao_contract.total_deposit + deposit_amount, deposit_transactions_count: dao_contract.deposit_transactions_count + deposit_transaction_ids.size, ) + update_addresses_dao_info(addresses_deposit_info) end @@ -406,11 +352,10 @@ def update_addresses_dao_info(addrs_deposit_info) id: address_id, dao_deposit: address_info[:dao_deposit], interest: address_info[:interest], - created_at: address_info[:created_at], - updated_at: Time.current, + is_depositor: address_info[:is_depositor], } end - Address.upsert_all(addresses_deposit_attributes) if addresses_deposit_attributes.present? + Address.upsert_all(addresses_deposit_attributes, record_timestamps: true) if addresses_deposit_attributes.present? end def update_or_create_udt_accounts!(local_block) @@ -712,14 +657,12 @@ def build_udts!(local_block, outputs, outputs_data) end def update_ckb_txs_rel_and_fee( - ckb_txs, tags, input_capacities, output_capacities, udt_address_ids, -dao_address_ids, contained_udt_ids, contained_addr_ids + ckb_txs, tags, input_capacities, output_capacities, udt_address_ids, contained_udt_ids, contained_addr_ids ) ckb_transactions_attributes = [] tx_index = 0 full_tx_address_ids = [] full_tx_udt_ids = [] - full_dao_address_ids = [] full_udt_address_ids = [] ckb_txs.each do |tx| tx_id = tx["id"] @@ -727,9 +670,6 @@ def update_ckb_txs_rel_and_fee( contained_addr_ids[tx_index].to_a.map do |a| { address_id: a, ckb_transaction_id: tx_id } end - full_dao_address_ids += dao_address_ids[tx_index].to_a.map do |a| - { address_id: a, ckb_transaction_id: tx_id } - end full_tx_udt_ids += contained_udt_ids[tx_index].to_a.map do |u| { udt_id: u, ckb_transaction_id: tx_id } end @@ -771,11 +711,6 @@ def update_ckb_txs_rel_and_fee( unique_by: %i[udt_id ckb_transaction_id] end - if full_dao_address_ids.present? - AddressDaoTransaction.upsert_all full_dao_address_ids, - unique_by: %i[address_id - ckb_transaction_id] - end if full_udt_address_ids.present? AddressUdtTransaction.upsert_all full_udt_address_ids, unique_by: %i[address_id @@ -785,7 +720,7 @@ def update_ckb_txs_rel_and_fee( def build_cells_and_locks!( local_block, node_block, ckb_txs, inputs, outputs, tags, udt_address_ids, - dao_address_ids, contained_udt_ids, contained_addr_ids, addrs_changes, token_transfer_ckb_tx_ids, cell_deps + contained_udt_ids, contained_addr_ids, addrs_changes, token_transfer_ckb_tx_ids, cell_deps ) cell_outputs_attributes = [] cell_inputs_attributes = [] @@ -805,7 +740,7 @@ def build_cells_and_locks!( # prepare script ids for insert cell_outputs prepare_script_ids(outputs) build_cell_outputs!(node_block, outputs, ckb_txs, local_block, cell_outputs_attributes, output_capacities, tags, - udt_address_ids, dao_address_ids, contained_udt_ids, contained_addr_ids, addrs_changes, token_transfer_ckb_tx_ids) + udt_address_ids, contained_udt_ids, contained_addr_ids, addrs_changes, token_transfer_ckb_tx_ids) if cell_outputs_attributes.present? tx_hashes = cell_outputs_attributes.map { |attr| attr[:tx_hash] } binary_hashes = CkbUtils.hexes_to_bins_sql(tx_hashes) @@ -859,7 +794,7 @@ def build_cells_and_locks!( prev_outputs = nil build_cell_inputs(inputs, ckb_txs, local_block.id, cell_inputs_attributes, prev_cell_outputs_attributes, - input_capacities, tags, udt_address_ids, dao_address_ids, contained_udt_ids, contained_addr_ids, + input_capacities, tags, udt_address_ids, contained_udt_ids, contained_addr_ids, prev_outputs, addrs_changes, token_transfer_ckb_tx_ids) CellInput.upsert_all(cell_inputs_attributes, @@ -953,7 +888,7 @@ def script_attributes(script, script_hash) def build_cell_inputs( inputs, ckb_txs, local_block_id, cell_inputs_attributes, prev_cell_outputs_attributes, -input_capacities, tags, udt_address_ids, dao_address_ids, contained_udt_ids, contained_addr_ids, prev_outputs, addrs_changes, token_transfer_ckb_tx_ids +input_capacities, tags, udt_address_ids, contained_udt_ids, contained_addr_ids, prev_outputs, addrs_changes, token_transfer_ckb_tx_ids ) tx_index = 0 @@ -994,7 +929,6 @@ def build_cell_inputs( cell_type = previous_output[:cell_type].to_s if cell_type.in?(%w(nervos_dao_withdrawing)) tags[tx_index] << "dao" - dao_address_ids[tx_index] << address_id change_rec[:dao_txs] ||= Set.new change_rec[:dao_txs] << ckb_txs[tx_index]["tx_hash"] elsif cell_type.in?(%w(m_nft_token nrc_721_token spore_cell did_cell)) @@ -1038,7 +972,7 @@ def build_cell_inputs( def build_cell_outputs!( node_block, outputs, ckb_txs, local_block, cell_outputs_attributes, output_capacities, -tags, udt_address_ids, dao_address_ids, contained_udt_ids, contained_addr_ids, addrs_changes, token_transfer_ckb_tx_ids +tags, udt_address_ids, contained_udt_ids, contained_addr_ids, addrs_changes, token_transfer_ckb_tx_ids ) outputs.each do |tx_index, items| cell_index = 0 @@ -1073,7 +1007,6 @@ def build_cell_outputs!( if attr[:cell_type].in?(%w(nervos_dao_deposit nervos_dao_withdrawing)) tags[tx_index] << "dao" - dao_address_ids[tx_index] << address.id change_rec[:dao_txs] ||= Set.new change_rec[:dao_txs] << ckb_txs[tx_index]["tx_hash"] end @@ -1482,7 +1415,7 @@ def update_address_balance_and_ckb_transactions_count(local_tip_block) address.live_cells_count = address.cell_outputs.live.count # address.ckb_transactions_count = address.custom_ckb_transactions.count address.ckb_transactions_count = AccountBook.where(address_id: address.id).count - address.dao_transactions_count = AddressDaoTransaction.where(address_id: address.id).count + address.dao_transactions_count = DaoEvent.processed.where(address_id: address.id).distinct(:ckb_transaction_id).count address.cal_balance! address.save! end diff --git a/app/models/ckb_transaction.rb b/app/models/ckb_transaction.rb index ef86f1dd9..0e36a4362 100644 --- a/app/models/ckb_transaction.rb +++ b/app/models/ckb_transaction.rb @@ -25,6 +25,7 @@ class CkbTransaction < ApplicationRecord has_many :inputs, class_name: "CellOutput", inverse_of: "consumed_by", foreign_key: "consumed_by_id" has_many :outputs, class_name: "CellOutput" has_many :dao_events + has_many :contained_dao_addresses, -> { distinct }, through: :dao_events, source: :address has_many :token_transfers, foreign_key: :transaction_id, inverse_of: :ckb_transaction has_many :cell_dependencies @@ -35,12 +36,11 @@ class CkbTransaction < ApplicationRecord has_and_belongs_to_many :contained_addresses, class_name: "Address", join_table: "account_books" has_and_belongs_to_many :contained_udts, class_name: "Udt", join_table: :udt_transactions - has_and_belongs_to_many :contained_dao_addresses, class_name: "Address", join_table: "address_dao_transactions" has_and_belongs_to_many :contained_udt_addresses, class_name: "Address", join_table: "address_udt_transactions" attribute :tx_hash, :ckb_hash - scope :recent, -> { order("block_timestamp desc nulls last, tx_index desc") } + scope :recent, -> { order("ckb_transactions.block_timestamp desc nulls last, ckb_transactions.tx_index desc") } scope :cellbase, -> { where(is_cellbase: true) } scope :normal, -> { where(is_cellbase: false) } scope :created_after, ->(block_timestamp) { where("block_timestamp >= ?", block_timestamp) } diff --git a/app/models/daily_statistic.rb b/app/models/daily_statistic.rb index 40f3b863b..63b8ca5bf 100644 --- a/app/models/daily_statistic.rb +++ b/app/models/daily_statistic.rb @@ -1,10 +1,12 @@ +# TODO +# remove dao_depositors_count daily_dao_withdraw nodes_distribution nodes_count average_block_time columns class DailyStatistic < ApplicationRecord include AttrLogics VALID_INDICATORS = %w( transactions_count addresses_count total_dao_deposit live_cells_count dead_cells_count avg_hash_rate avg_difficulty uncle_rate total_depositors_count address_balance_distribution total_tx_fee occupied_capacity daily_dao_deposit daily_dao_depositors_count - circulation_ratio daily_dao_withdraw nodes_count circulating_supply burnt locked_capacity treasury_amount mining_reward + circulation_ratio nodes_count circulating_supply burnt locked_capacity treasury_amount mining_reward deposit_compensation liquidity created_at_unixtimestamp ckb_hodl_wave holder_count knowledge_size activity_address_contract_distribution ).freeze MILLISECONDS_IN_DAY = BigDecimal(24 * 60 * 60 * 1000) @@ -54,24 +56,12 @@ def liquidity withdraw_amount = DaoEvent.processed.withdraw_from_dao.created_before(ended_at).sum(:value) total_dao_deposit = deposit_amount - withdraw_amount else - daily_dao_withdraw = @daily_dao_withdraw ||= DaoEvent.processed.withdraw_from_dao.created_after(started_at).created_before(ended_at).sum(:value) - daily_dao_deposit = @daily_dao_deposit ||= DaoEvent.processed.deposit_to_dao.created_after(started_at).created_before(ended_at).sum(:value) + daily_dao_withdraw = DaoEvent.processed.withdraw_from_dao.created_after(started_at).created_before(ended_at).sum(:value) total_dao_deposit = daily_dao_deposit - daily_dao_withdraw + yesterday_daily_statistic.total_dao_deposit.to_i end total_dao_deposit end - define_logic :dao_depositors_count do - dao_depositors_count = "" - if from_scratch - dao_depositors_count = total_depositors_count.to_i - DaoEvent.processed.take_away_all_deposit.created_before(ended_at).count - else - withdrawals_today = DaoEvent.processed.take_away_all_deposit.created_after(started_at).created_before(ended_at).count - dao_depositors_count = daily_dao_depositors_count.to_i - withdrawals_today + yesterday_daily_statistic.dao_depositors_count.to_i - end - dao_depositors_count - end - define_logic :unclaimed_compensation do phase1_dao_interests + unmade_dao_interests end @@ -174,13 +164,11 @@ def liquidity end define_logic :total_depositors_count do - @total_depositors_count ||= - if from_scratch - DaoEvent.processed.new_dao_depositor.created_before(ended_at).count - else - new_depositors_count_today = processed_dao_events_in_current_period.new_dao_depositor.count - new_depositors_count_today + yesterday_daily_statistic.total_depositors_count.to_i - end + @total_depositors_count ||= if from_scratch + DaoEvent.created_before(ended_at).deposit_to_dao.distinct.count(:address_id) + else + daily_dao_depositors_count + yesterday_daily_statistic.total_depositors_count.to_i + end end define_logic :address_balance_distribution do @@ -222,11 +210,10 @@ def liquidity end define_logic :daily_dao_depositors_count do - processed_dao_events_in_current_period.new_dao_depositor.count - end - - define_logic :daily_dao_withdraw do - processed_dao_events_in_current_period.withdraw_from_dao.sum(:value) + processed_dao_events_in_current_period. + deposit_to_dao. + where.not(address_id: DaoEvent.created_before(started_at).depositor. + select(:address_id)).distinct.count(:address_id) end define_logic :circulation_ratio do @@ -513,12 +500,8 @@ def total_difficulties_for_the_day end end - def dao_events_in_current_period - @dao_events_in_current_period ||= DaoEvent.created_between(started_at, ended_at) - end - def processed_dao_events_in_current_period - @processed_dao_events_in_current_period ||= dao_events_in_current_period.processed + @processed_dao_events_in_current_period ||= DaoEvent.created_between(started_at, ended_at).processed end def yesterday_daily_statistic @@ -529,7 +512,7 @@ def yesterday_daily_statistic if to_be_counted_date.beginning_of_day.to_i == Time.at(GENESIS_TIMESTAMP / 1000).in_time_zone.beginning_of_day.to_i \ || aggron_first_day? \ || yesterday_statistic.blank? - OpenStruct.new(addresses_count: 0, total_dao_deposit: 0, dao_depositors_count: 0, + OpenStruct.new(addresses_count: 0, total_dao_deposit: 0, unclaimed_compensation: 0, claimed_compensation: 0, average_deposit_time: 0, mining_reward: 0, deposit_compensation: 0, treasury_amount: 0, total_depositors_count: 0, diff --git a/app/models/dao_contract.rb b/app/models/dao_contract.rb index 9c87c5529..20110aad2 100644 --- a/app/models/dao_contract.rb +++ b/app/models/dao_contract.rb @@ -1,5 +1,5 @@ class DaoContract < ApplicationRecord - validates :total_deposit, :claimed_compensation, :deposit_transactions_count, :withdraw_transactions_count, :depositors_count, :total_depositors_count, presence: true, numericality: { greater_than_or_equal_to: 0 } + validates :total_deposit, :claimed_compensation, :deposit_transactions_count, :withdraw_transactions_count, :depositors_count, presence: true, numericality: { greater_than_or_equal_to: 0 } CONTRACT_NAME = "nervos_dao".freeze GENESIS_ISSUANCE = 336 * 10**8 ANNUAL_PRIMARY_ISSUANCE_BASE = GENESIS_ISSUANCE / 8 @@ -84,7 +84,8 @@ def tip_block_fraction_epoch end def latest_daily_statistic - @latest_daily_statistic ||= DailyStatistic.recent.first || OpenStruct.new(total_dao_deposit: 0, dao_depositors_count: 0, unclaimed_compensation: 0, claimed_compensation: 0, average_deposit_time: 0, mining_reward: 0, deposit_compensation: 0, treasury_amount: 0) + @latest_daily_statistic ||= DailyStatistic.recent.first || OpenStruct.new(total_dao_deposit: 0, dao_depositors_count: 0, unclaimed_compensation: 0, claimed_compensation: 0, + average_deposit_time: 0, mining_reward: 0, deposit_compensation: 0, treasury_amount: 0) end def alpha(start_epoch_number) diff --git a/app/models/dao_event.rb b/app/models/dao_event.rb index fd33ee514..9a038ff6d 100644 --- a/app/models/dao_event.rb +++ b/app/models/dao_event.rb @@ -5,10 +5,8 @@ class DaoEvent < ApplicationRecord # withdraw_phase_2: issue_interest enum event_type: { deposit_to_dao: 0, - new_dao_depositor: 1, withdraw_from_dao: 2, issue_interest: 3, - take_away_all_deposit: 4 } enum status: { pending: 0, processed: 1, reverted: 2 } validates :value, presence: true, numericality: { greater_than_or_equal_to: 0 } @@ -17,37 +15,12 @@ class DaoEvent < ApplicationRecord belongs_to :ckb_transaction belongs_to :address + scope :depositor, -> { processed.where(event_type: "deposit_to_dao", withdrawn_transaction_id: nil) } scope :created_after, ->(block_timestamp) { where("block_timestamp >= ?", block_timestamp) } scope :created_before, ->(block_timestamp) { where("block_timestamp <= ?", block_timestamp) } scope :created_between, ->(start_block_timestamp, end_block_timestamp) { created_after(start_block_timestamp).created_before(end_block_timestamp) } - - def get_froms - froms = - case event_type - when "deposit_to_dao" - ckb_transaction.display_inputs.map do |display_input| - CkbUtils.generate_address(CkbUtils.parse_address(display_input[:address_hash]).script) - end - when "withdraw_from_dao" - ckb_transaction.display_inputs.select { |display_input| - display_input[:cell_type] == "nervos_dao_deposit" - }.map do |display_input| - CkbUtils.generate_address(CkbUtils.parse_address(display_input[:address_hash]).script) - end - when "issue_interest" - ckb_transaction.display_inputs.select { |display_input| - display_input[:cell_type] == "nervos_dao_withdrawing" - }.map do |display_input| - CkbUtils.generate_address(CkbUtils.parse_address(display_input[:address_hash]).script) - end - else - [] - end - - return froms - end end # == Schema Information @@ -70,7 +43,8 @@ def get_froms # # Indexes # -# index_dao_events_on_block_id (block_id) -# index_dao_events_on_block_timestamp (block_timestamp) -# index_dao_events_on_status_and_event_type (status,event_type) +# index_dao_events_on_block_id (block_id) +# index_dao_events_on_block_id_tx_id_and_index_and_type (block_id,ckb_transaction_id,cell_index,event_type) UNIQUE +# index_dao_events_on_block_timestamp (block_timestamp) +# index_dao_events_on_status_and_event_type (status,event_type) # diff --git a/app/services/charts/daily_statistic_generator.rb b/app/services/charts/daily_statistic_generator.rb index 0043dd275..ddf801bec 100644 --- a/app/services/charts/daily_statistic_generator.rb +++ b/app/services/charts/daily_statistic_generator.rb @@ -28,14 +28,14 @@ def call def updated_attrs # next attrs were generated by before attrs, so they should have an order to reset established_order = %i{ - total_depositors_count daily_dao_depositors_count dao_depositors_count unclaimed_compensation claimed_compensation deposit_compensation total_dao_deposit circulating_supply circulation_ratio + daily_dao_depositors_count total_depositors_count unclaimed_compensation claimed_compensation deposit_compensation daily_dao_deposit total_dao_deposit circulating_supply circulation_ratio } others = %i{ - block_timestamp transactions_count addresses_count daily_dao_withdraw + block_timestamp transactions_count addresses_count average_deposit_time mining_reward knowledge_size treasury_amount estimated_apc live_cells_count dead_cells_count avg_hash_rate avg_difficulty uncle_rate address_balance_distribution - total_tx_fee occupied_capacity daily_dao_deposit total_supply block_time_distribution + total_tx_fee occupied_capacity total_supply block_time_distribution epoch_time_distribution epoch_length_distribution locked_capacity ckb_hodl_wave holder_count activity_address_contract_distribution } diff --git a/db/migrate/20241223023654_remove_address_dao_transaction.rb b/db/migrate/20241223023654_remove_address_dao_transaction.rb new file mode 100644 index 000000000..f5714e28a --- /dev/null +++ b/db/migrate/20241223023654_remove_address_dao_transaction.rb @@ -0,0 +1,5 @@ +class RemoveAddressDaoTransaction < ActiveRecord::Migration[7.0] + def change + drop_table :address_dao_transactions, if_exists: true + end +end diff --git a/db/migrate/20241231022644_add_unique_index_to_dao_event.rb b/db/migrate/20241231022644_add_unique_index_to_dao_event.rb new file mode 100644 index 000000000..c73e9a237 --- /dev/null +++ b/db/migrate/20241231022644_add_unique_index_to_dao_event.rb @@ -0,0 +1,5 @@ +class AddUniqueIndexToDaoEvent < ActiveRecord::Migration[7.0] + def change + add_index :dao_events, %i[block_id ckb_transaction_id cell_index event_type], unique: true, name: "index_dao_events_on_block_id_tx_id_and_index_and_type" + end +end diff --git a/db/structure.sql b/db/structure.sql index 1b35e256c..fb806dee9 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -379,16 +379,6 @@ CREATE SEQUENCE public.address_block_snapshots_id_seq ALTER SEQUENCE public.address_block_snapshots_id_seq OWNED BY public.address_block_snapshots.id; --- --- Name: address_dao_transactions; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.address_dao_transactions ( - ckb_transaction_id bigint, - address_id bigint -); - - -- -- Name: address_udt_transactions; Type: TABLE; Schema: public; Owner: - -- @@ -4172,13 +4162,6 @@ ALTER TABLE ONLY public.xudt_tags ADD CONSTRAINT xudt_tags_pkey PRIMARY KEY (id); --- --- Name: address_dao_tx_alt_pk; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX address_dao_tx_alt_pk ON public.address_dao_transactions USING btree (address_id, ckb_transaction_id); - - -- -- Name: address_udt_tx_alt_pk; Type: INDEX; Schema: public; Owner: - -- @@ -4711,13 +4694,6 @@ CREATE INDEX index_address_block_snapshots_on_block_id ON public.address_block_s CREATE UNIQUE INDEX index_address_block_snapshots_on_block_id_and_address_id ON public.address_block_snapshots USING btree (block_id, address_id); --- --- Name: index_address_dao_transactions_on_ckb_transaction_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_address_dao_transactions_on_ckb_transaction_id ON public.address_dao_transactions USING btree (ckb_transaction_id); - - -- -- Name: index_address_udt_transactions_on_ckb_transaction_id; Type: INDEX; Schema: public; Owner: - -- @@ -5047,6 +5023,13 @@ CREATE UNIQUE INDEX index_daily_statistics_on_created_at_unixtimestamp ON public CREATE INDEX index_dao_events_on_block_id ON public.dao_events USING btree (block_id); +-- +-- Name: index_dao_events_on_block_id_tx_id_and_index_and_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_dao_events_on_block_id_tx_id_and_index_and_type ON public.dao_events USING btree (block_id, ckb_transaction_id, cell_index, event_type); + + -- -- Name: index_dao_events_on_block_timestamp; Type: INDEX; Schema: public; Owner: - -- @@ -6331,7 +6314,9 @@ INSERT INTO "schema_migrations" (version) VALUES ('20241212022531'), ('20241213053309'), ('20241218085721'), +('20241223023654'), ('20241223060331'), -('20241225045757'); +('20241225045757'), +('20241231022644'); diff --git a/lib/tasks/migration/check_dao_event.rake b/lib/tasks/migration/check_dao_event.rake new file mode 100644 index 000000000..4be6cb1ef --- /dev/null +++ b/lib/tasks/migration/check_dao_event.rake @@ -0,0 +1,36 @@ +namespace :migration do + desc "Usage: RAILS_ENV=production bundle exec rake migration:check_dao_event" + task check_dao_event: :environment do + error_tx_ids = [] + CkbTransaction.where("tags @> array[?]::varchar[]", ["dao"]).find_each do |tx| + tx.outputs.where(cell_type: :nervos_dao_deposit).each do |output| + unless DaoEvent.where(ckb_transaction_id: tx.id, address_id: output.address_id, value: output.capacity, event_type: "deposit_to_dao", cell_index: output.cell_index).exists? + error_tx_ids << tx.id + end + end + tx.cell_inputs.where(cell_type: :nervos_dao_withdrawing).each do |input| + previous_cell_output = CellOutput. + where(id: input.previous_cell_output_id). + select(:address_id, :block_id, :ckb_transaction_id, :dao, :cell_index, :capacity, :occupied_capacity). + take! + interest = CkbUtils.dao_interest(previous_cell_output) + unless DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: interest, event_type: "issue_interest", cell_index: input.index).exists? + error_tx_ids << tx.id + + end + end + tx.cell_inputs.where(cell_type: :nervos_dao_deposit).each do |input| + previous_cell_output = + CellOutput. + where(id: input.previous_cell_output_id). + select(:address_id, :ckb_transaction_id, :cell_index, :capacity). + take! + unless DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: previous_cell_output.capacity, event_type: "withdraw_from_dao", + cell_index: input.index).exists? + error_tx_ids << tx.id + end + end + end + puts error_tx_ids.join(",") + end +end diff --git a/lib/tasks/migration/fill_cell_index_to_dao_event.rake b/lib/tasks/migration/fill_cell_index_to_dao_event.rake index 75d60e9d3..cfc903fed 100644 --- a/lib/tasks/migration/fill_cell_index_to_dao_event.rake +++ b/lib/tasks/migration/fill_cell_index_to_dao_event.rake @@ -1,7 +1,8 @@ namespace :migration do desc "Usage: RAILS_ENV=production bundle exec rake migration:fill_cell_index_to_dao_event" task fill_cell_index_to_dao_event: :environment do - CellOutput.dead.where(cell_type: ["nervos_dao_deposit", "nervos_dao_withdrawing"]).find_each do |output| + ActiveRecord::Base.connection.execute("SET statement_timeout = 0") + CellOutput.includes(:cell_inputs).dead.where(cell_type: ["nervos_dao_deposit", "nervos_dao_withdrawing"]).find_each do |output| input = output.cell_inputs.first if input.cell_type != output.cell_type puts "input id: #{input.id}" @@ -10,12 +11,14 @@ namespace :migration do end CkbTransaction.where("tags @> array[?]::varchar[]", ["dao"]).find_each do |tx| tx.outputs.where(cell_type: :nervos_dao_deposit).each do |output| - event = DaoEvent.where(ckb_transaction_id: tx.id, address_id: output.address_id, value: output.capacity, event_type: "deposit_to_dao", cell_index: nil).limit(1).first - if event - event.update(cell_index: output.cell_index) - else - DaoEvent.create(ckb_transaction_id: tx.id, address_id: output.address_id, value: output.capacity, event_type: "deposit_to_dao", cell_index: output.cell_index, block_id: tx.block_id, - block_timestamp: tx.block_timestamp, contract_id: 1) + unless DaoEvent.where(ckb_transaction_id: tx.id, address_id: output.address_id, value: output.capacity, event_type: "deposit_to_dao", cell_index: output.cell_index).exists? + event = DaoEvent.where(ckb_transaction_id: tx.id, address_id: output.address_id, value: output.capacity, event_type: "deposit_to_dao", cell_index: nil).limit(1).first + if event + event.update(cell_index: output.cell_index) + else + DaoEvent.create(ckb_transaction_id: tx.id, address_id: output.address_id, value: output.capacity, event_type: "deposit_to_dao", status: "processed", cell_index: output.cell_index, block_id: tx.block_id, + block_timestamp: tx.block_timestamp, contract_id: 1) + end end end tx.cell_inputs.where(cell_type: :nervos_dao_withdrawing).each do |input| @@ -24,12 +27,14 @@ namespace :migration do select(:address_id, :block_id, :ckb_transaction_id, :dao, :cell_index, :capacity, :occupied_capacity). take! interest = CkbUtils.dao_interest(previous_cell_output) - event = DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: interest, event_type: "issue_interest", cell_index: nil).limit(1).first - if event - event.update(cell_index: input.index) - else - DaoEvent.create(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: interest, event_type: "issue_interest", cell_index: input.index, block_id: tx.block_id, - block_timestamp: tx.block_timestamp, contract_id: 1) + unless DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: interest, event_type: "issue_interest", cell_index: input.index).exists? + event = DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: interest, event_type: "issue_interest", cell_index: nil).limit(1).first + if event + event.update(cell_index: input.index) + else + DaoEvent.create(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: interest, event_type: "issue_interest", status: "processed", cell_index: input.index, block_id: tx.block_id, + block_timestamp: tx.block_timestamp, contract_id: 1) + end end end tx.cell_inputs.where(cell_type: :nervos_dao_deposit).each do |input| @@ -38,15 +43,16 @@ namespace :migration do where(id: input.previous_cell_output_id). select(:address_id, :ckb_transaction_id, :cell_index, :capacity). take! - event = DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: previous_cell_output.capacity, event_type: "withdraw_from_dao", - cell_index: nil).limit(1).first - DaoEvent.find_by(ckb_transaction_id: previous_cell_output.ckb_transaction_id, address_id: previous_cell_output.address_id, value: previous_cell_output.capacity, event_type: "deposit_to_dao", - cell_index: previous_cell_output.cell_index).update(withdrawn_transaction_id: tx.id) - if event - event.update(cell_index: input.index) - else - DaoEvent.create(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: previous_cell_output.capacity, event_type: "withdraw_from_dao", cell_index: input.index, block_id: tx.block_id, - block_timestamp: tx.block_timestamp, contract_id: 1) + unless DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: previous_cell_output.capacity, event_type: "withdraw_from_dao", + cell_index: input.index).exists? + event = DaoEvent.where(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: previous_cell_output.capacity, event_type: "withdraw_from_dao", + cell_index: nil).limit(1).first + if event + event.update(cell_index: input.index) + else + DaoEvent.create(ckb_transaction_id: tx.id, address_id: previous_cell_output.address_id, value: previous_cell_output.capacity, event_type: "withdraw_from_dao", status: "processed", cell_index: input.index, block_id: tx.block_id, + block_timestamp: tx.block_timestamp, contract_id: 1) + end end end end diff --git a/test/controllers/api/v1/contract_transactions_controller_test.rb b/test/controllers/api/v1/contract_transactions_controller_test.rb index 6c352ce5f..5b083eb10 100644 --- a/test/controllers/api/v1/contract_transactions_controller_test.rb +++ b/test/controllers/api/v1/contract_transactions_controller_test.rb @@ -213,7 +213,8 @@ class ContractTransactionsControllerTest < ActionDispatch::IntegrationTest contract_ckb_transactions = address.ckb_dao_transactions.joins(:account_books). where(account_books: { address_id: address.id }). - order("ckb_transactions.block_timestamp desc nulls last, ckb_transactions.id desc").page(page).per(page_size).fast_page + select(:id, :tx_hash, :block_id, :block_number, :block_timestamp, :is_cellbase, :updated_at, :created_at, :tags). + order("ckb_transactions.block_timestamp desc nulls last, ckb_transactions.id desc").page(page).per(page_size) valid_get api_v1_contract_transaction_url(DaoContract::CONTRACT_NAME), params: { page:, page_size:, address_hash: address.address_hash } 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/factories/ckb_transaction.rb b/test/factories/ckb_transaction.rb index 9bb5d473f..6e76113be 100644 --- a/test/factories/ckb_transaction.rb +++ b/test/factories/ckb_transaction.rb @@ -35,9 +35,6 @@ header_hash: header_dep, index: i) end end - if eval.cell_deps.present? - DeployedCell.create_initial_data_for_ckb_transaction tx, eval.cell_deps - end end transient do diff --git a/test/factories/lock_script.rb b/test/factories/lock_script.rb index becd0133a..5d97cbd70 100644 --- a/test/factories/lock_script.rb +++ b/test/factories/lock_script.rb @@ -4,5 +4,8 @@ hash_type { "type" } args { "0x#{SecureRandom.hex(20)}" } code_hash { Settings.secp_cell_type_hash } + before(:create) do |lock_script| + lock_script.script_hash = CKB::Types::Script.new(code_hash: lock_script.code_hash, hash_type: lock_script.hash_type, args: lock_script.args).compute_hash + end end end diff --git a/test/models/address_test.rb b/test/models/address_test.rb index 45617d697..93c1551f0 100644 --- a/test/models/address_test.rb +++ b/test/models/address_test.rb @@ -202,12 +202,11 @@ class AddressTest < ActiveSupport::TestCase 30.times do |number| block = create(:block, :with_block_hash) contained_address_ids = number % 2 == 0 ? [address.id] : [address1.id] - tx = create(:ckb_transaction, block:, tags: ["dao"], contained_dao_address_ids: contained_address_ids, - contained_address_ids:) + tx = create(:ckb_transaction, block:, tags: ["dao"], contained_address_ids:) + create(:dao_event, block:, address_id: contained_address_ids[0], + ckb_transaction_id: tx.id) AccountBook.find_or_create_by(address_id: contained_address_ids[0], ckb_transaction: tx) - AddressDaoTransaction.insert({ address_id: contained_address_ids[0], - ckb_transaction_id: tx.id }) cell_type = number % 2 == 0 ? "nervos_dao_deposit" : "nervos_dao_withdrawing" cell_output_address = number % 2 == 0 ? address : address1 create(:cell_output, block:, address: cell_output_address, @@ -221,13 +220,13 @@ class AddressTest < ActiveSupport::TestCase expected_ckb_transactions = CkbTransaction.where(id: ckb_transaction_ids).recent assert_equal expected_ckb_transactions.pluck(:id).sort, - address.ckb_dao_transactions.recent.pluck(:id).sort + address.ckb_dao_transactions.select(:id, :block_timestamp, :tx_index).recent.map { |tx| tx.id }.sort end test "#ckb_dao_transactions should return an empty array when there aren't dao cell" do address = create(:address) - assert_equal [], address.ckb_dao_transactions.recent.pluck(:id) + assert_equal [], address.ckb_dao_transactions.select(:id, :block_timestamp, :tx_index).recent.map { |tx| tx.id } end test "#ckb_udt_transactions should return correct ckb transactions with udt cell when there are udt cells" do diff --git a/test/models/ckb_sync/dao_events_test.rb b/test/models/ckb_sync/dao_events_test.rb index 4198fde77..185477dcf 100644 --- a/test/models/ckb_sync/dao_events_test.rb +++ b/test/models/ckb_sync/dao_events_test.rb @@ -71,9 +71,9 @@ class DaoEventsTest < ActiveSupport::TestCase deposit_to_dao_events = Block.find_by(number: node_block.header.number).dao_events.where(event_type: "withdraw_from_dao") 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 { |attribute| + 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)) - } + end) end end @@ -116,26 +116,6 @@ class DaoEventsTest < ActiveSupport::TestCase end end - test "#process_block should decrease dao contract depositors count when previous output is a dao cell and address interest change to zero" do - DaoCompensationCalculator.any_instance.stubs(:call).returns(1000) - 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 - tx = fake_dao_withdraw_transaction(node_block) - output = tx.cell_outputs.first - address = output.address - address.update(dao_deposit: output.capacity) - DaoContract.default_contract.update(total_deposit: 100000000000, depositors_count: 1) - - assert_difference -> { DaoContract.default_contract.reload.depositors_count }, -1 do - node_data_processor.process_block(node_block) - end - - take_away_all_deposit_events = Block.find_by(number: node_block.header.number).dao_events.where(event_type: "take_away_all_deposit") - assert_equal ["processed"], take_away_all_deposit_events.pluck(:status).uniq - end - end - test "should update tx's tags when input have nervos_dao_withdrawing cells" do DaoContract.default_contract.update(total_deposit: 100000000000000) block1 = create(:block, :with_block_hash, number: DEFAULT_NODE_BLOCK_NUMBER - 2) @@ -320,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 @@ -381,48 +361,24 @@ class DaoEventsTest < ActiveSupport::TestCase end end - test "should increase dao contract depositors_count when block is invalid and previous output is a dao cell" do - DaoCompensationCalculator.any_instance.stubs(:call).returns(1000) - DaoContract.default_contract.update(total_deposit: 100000000000000, depositors_count: 1) - node_block = fake_node_block("0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") - create(:block, :with_block_hash, number: node_block.header.number - 1, timestamp: 1557282351075) - VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do - tx = fake_dao_withdraw_transaction(node_block) - output = tx.cell_outputs.first - address = output.address - address.update(dao_deposit: output.capacity) - node_data_processor.process_block(node_block) - end - - local_block = Block.find_by(block_hash: "0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") - local_block.update(block_hash: "0x419c632366c8eb9635acbb39ea085f7552ae62e1fdd480893375334a0f37d1bx") - - VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", record: :new_episodes) do - assert_difference -> { DaoContract.default_contract.depositors_count }, 1 do - node_data_processor.call - end - - deposit_to_dao_events = local_block.dao_events.where(event_type: "take_away_all_deposit") - assert_equal ["reverted"], deposit_to_dao_events.pluck(:status).uniq - end - end - test "#process_block should create dao_event which event_type is withdraw_from_dao when previous output is a dao cell" do DaoCompensationCalculator.any_instance.stubs(:call).returns(1000) 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 { |attribute| + 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)) - } + end) end end @@ -443,40 +399,6 @@ class DaoEventsTest < ActiveSupport::TestCase end end - test "#process_block should create dao_event which event_type is take away all deposit when previous output is a dao cell and address interest change to zero" do - DaoCompensationCalculator.any_instance.stubs(:call).returns(1000) - DaoContract.default_contract.update(total_deposit: 100000000000000, depositors_count: 1) - 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 - tx = fake_dao_withdraw_transaction(node_block) - output = tx.cell_outputs.first - address = output.address - address.update(dao_deposit: output.capacity) - - assert_difference -> { DaoEvent.where(event_type: "take_away_all_deposit").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: "take_away_all_deposit") - assert_equal ["processed"], deposit_to_dao_events.pluck(:status).uniq - end - end - - test "#process_block should keep address deposit 0 when only have dao withdrawal event" do - DaoContract.default_contract.update(total_deposit: 100000000000000, depositors_count: 1) - DaoCompensationCalculator.any_instance.stubs(:call).returns(1000) - 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 - tx = fake_dao_withdraw_transaction(node_block) - output = tx.cell_outputs.first - address = output.address - - assert_equal 0, address.reload.dao_deposit - end - end - test "#process_block should increase address interest when previous output is a withdrawing cell" do DaoCompensationCalculator.any_instance.stubs(:call).returns(100800000000) DaoContract.default_contract.update(total_deposit: 100000000000000, depositors_count: 1) @@ -506,9 +428,9 @@ class DaoEventsTest < ActiveSupport::TestCase init_interest_granted = 10**8 * 100 init_deposit_transactions_count = 2 init_withdraw_transactions_count = 1 - init_total_depositors_count = 2 dao_contract.update(total_deposit: init_total_deposit, depositors_count: init_depositors_count, - claimed_compensation: init_interest_granted, deposit_transactions_count: init_deposit_transactions_count, withdraw_transactions_count: init_withdraw_transactions_count, total_depositors_count: init_total_depositors_count) + claimed_compensation: init_interest_granted, deposit_transactions_count: init_deposit_transactions_count, withdraw_transactions_count: init_withdraw_transactions_count) + create_list(:dao_event, 3, status: :processed, contract_id: 1, event_type: "deposit_to_dao") prepare_node_data(HAS_UNCLES_BLOCK_NUMBER) local_block = Block.find_by(number: HAS_UNCLES_BLOCK_NUMBER) local_block.update(block_hash: "0x419c632366c8eb9635acbb39ea085f7552ae62e1fdd480893375334a0f37d1bx") @@ -521,7 +443,6 @@ class DaoEventsTest < ActiveSupport::TestCase assert_equal init_interest_granted, dao_contract.claimed_compensation assert_equal init_deposit_transactions_count, dao_contract.deposit_transactions_count assert_equal init_withdraw_transactions_count, dao_contract.withdraw_transactions_count - assert_equal init_total_depositors_count, dao_contract.total_depositors_count end end @@ -613,40 +534,6 @@ class DaoEventsTest < ActiveSupport::TestCase end end - test "should revert dao contract depositors count when block is invalid and there is dao cell" do - CkbSync::Api.any_instance.stubs(:calculate_dao_maximum_withdraw).returns("0x2faf0be8") - node_block = fake_node_block - create(:block, :with_block_hash, number: node_block.header.number - 1, timestamp: 1557282351075) - VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do - fake_dao_deposit_transaction(node_block) - node_data_processor.process_block(node_block) - end - dao_contract = DaoContract.default_contract - local_block = Block.find_by(number: DEFAULT_NODE_BLOCK_NUMBER) - local_block.update(block_hash: "0x419c632366c8eb9635acbb39ea085f7552ae62e1fdd480893375334a0f37d1bx") - VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", record: :new_episodes) do - assert_difference -> { dao_contract.reload.depositors_count }, -1 do - node_data_processor.call - end - - deposit_to_dao_events = local_block.dao_events.where(event_type: "new_dao_depositor") - assert_equal ["reverted"], deposit_to_dao_events.pluck(:status).uniq - end - end - - test "#process_block should create dao_event which event_type is new_dao_depositor when output is a dao cell" do - CkbSync::Api.any_instance.stubs(:calculate_dao_maximum_withdraw).returns("0x2faf0be8") - 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_deposit_transaction(node_block) - - assert_difference -> { DaoEvent.where(event_type: "new_dao_depositor").count }, 1 do - node_data_processor.process_block(node_block) - end - end - end - test "#process_block should update address deposits when dao_event is deposit_to_dao and output is a dao cell" do CkbSync::Api.any_instance.stubs(:calculate_dao_maximum_withdraw).returns("0x2faf0be8") node_block = fake_node_block("0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") @@ -655,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) @@ -662,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 @@ -698,46 +587,6 @@ class DaoEventsTest < ActiveSupport::TestCase end end - test "#process_block should update dao contract depositors count when dao_event is new_dao_depositor and output is a dao cell" do - CkbSync::Api.any_instance.stubs(:calculate_dao_maximum_withdraw).returns("0x2faf0be8") - - 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_deposit_transaction(node_block) - - assert_difference -> { DaoContract.default_contract.depositors_count }, 1 do - node_data_processor.process_block(node_block) - end - end - - deposit_to_dao_events = Block.find_by(number: node_block.header.number).dao_events.where(event_type: "new_dao_depositor") - assert_equal ["processed"], deposit_to_dao_events.pluck(:status).uniq - assert_not_empty DaoEvent.where(event_type: "new_dao_depositor") - end - - test "#process_block should update dao contract total depositors count when dao_event is new_dao_depositor and output is a dao cell" do - CkbSync::Api.any_instance.stubs(:calculate_dao_maximum_withdraw).returns("0x2faf0be8") - - 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_deposit_transaction(node_block) - - assert_difference -> { DaoContract.default_contract.total_depositors_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: "new_dao_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 { |attribute| - attribute.in?(%w(created_at updated_at id)) - } - end - end - test "#process_block should not update dao contract total depositors count when depositors is already has been recorded" do DaoContract.default_contract.update(total_deposit: 100000000000000, depositors_count: 1, total_depositors_count: 1) @@ -807,11 +656,11 @@ class DaoEventsTest < ActiveSupport::TestCase tx3 = create(:ckb_transaction, block: block2) tx4 = create(:ckb_transaction, block: block2) tx5 = create(:ckb_transaction, block: block2) - input_address1 = create(:address) - input_address2 = create(:address) + input_address1 = create(:address, dao_deposit: 50000 * 10**8) + input_address2 = create(:address, dao_deposit: 60000 * 10**8) input_address3 = create(:address) - input_address4 = create(:address) - input_address5 = create(:address) + input_address4 = create(:address, dao_deposit: 70000 * 10**8) + input_address5 = create(:address, dao_deposit: 70000 * 10**8) create(:cell_output, ckb_transaction: tx1, block: block1, capacity: 50000 * 10**8, tx_hash: tx1.tx_hash, cell_index: 0, address: input_address1, cell_type: "nervos_dao_deposit") create(:cell_output, ckb_transaction: tx2, block: block2, capacity: 60000 * 10**8, tx_hash: tx2.tx_hash, @@ -889,8 +738,8 @@ class DaoEventsTest < ActiveSupport::TestCase block2 = create(:block, :with_block_hash, number: DEFAULT_NODE_BLOCK_NUMBER - 1) tx2 = create(:ckb_transaction, block: block2) tx3 = create(:ckb_transaction, block: block2) - input_address1 = create(:address) - input_address2 = create(:address) + input_address1 = create(:address, dao_deposit: 50000 * 10**8) + input_address2 = create(:address, dao_deposit: 60000 * 10**8) input_address3 = create(:address) create(:cell_output, ckb_transaction: tx1, block: block1, capacity: 50000 * 10**8, tx_hash: tx1.tx_hash, cell_index: 0, address: input_address1, cell_type: "nervos_dao_deposit") @@ -975,10 +824,11 @@ 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) + 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 + output.type = CKB::Types::Script.new(args: "0xb2e61ff569acf041b3c2c17724e2379c581eeac3", hash_type: "type", code_hash: Settings.dao_type_hash) tx.outputs_data[0] = CKB::Utils.bin_to_hex("\x02" * 8) diff --git a/test/models/ckb_sync/node_data_processor_test.rb b/test/models/ckb_sync/node_data_processor_test.rb index 8e3fdf367..56681f09b 100644 --- a/test/models/ckb_sync/node_data_processor_test.rb +++ b/test/models/ckb_sync/node_data_processor_test.rb @@ -421,9 +421,9 @@ class NodeDataProcessorTest < ActiveSupport::TestCase local_block = node_data_processor.process_block(node_block) expected_capacity_involved = local_block.ckb_transactions.normal.map(&:capacity_involved) - assert_equal expected_capacity_involved, local_block.ckb_transactions.normal.map { |transaction| + assert_equal(expected_capacity_involved, local_block.ckb_transactions.normal.map do |transaction| transaction.inputs.sum(:capacity) - } + end) end end @@ -828,12 +828,12 @@ class NodeDataProcessorTest < ActiveSupport::TestCase VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", record: :new_episodes) do assert_difference -> { - dao_contract.reload.total_depositors_count + dao_contract.reload.depositors_count }, -1 do node_data_processor.call end - deposit_to_dao_events = local_block.dao_events.where(event_type: "new_dao_depositor") + deposit_to_dao_events = local_block.dao_events.where(event_type: "deposit_to_dao") assert_equal ["reverted"], deposit_to_dao_events.pluck(:status).uniq end end @@ -1254,6 +1254,7 @@ class NodeDataProcessorTest < ActiveSupport::TestCase address2 = Address.find_by(lock_hash: lock2.compute_hash) address3 = Address.find_by(lock_hash: lock3.compute_hash) 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 node_data_processor.call @@ -2624,11 +2625,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 @@ -3135,7 +3137,7 @@ class NodeDataProcessorTest < ActiveSupport::TestCase ] inputs1 = [ CKB::Types::Input.new(previous_output: CKB::Types::OutPoint.new(tx_hash: tx4.tx_hash, index: 0)), # nervos_dao_withdrawing cell - CKB::Types::Input.new(previous_output: CKB::Types::OutPoint.new(tx_hash: tx5.tx_hash, index: 0)), # udt cell + CKB::Types::Input.new(previous_output: CKB::Types::OutPoint.new(tx_hash: tx5.tx_hash, index: 0)), # udt cell ] lock1 = CKB::Types::Script.new( code_hash: Settings.secp_cell_type_hash, @@ -3838,7 +3840,7 @@ class NodeDataProcessorTest < ActiveSupport::TestCase Sidekiq::Testing.inline! 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 node_data_processor.call diff --git a/test/models/dao_contract_test.rb b/test/models/dao_contract_test.rb index ece1fa62d..a349e9334 100644 --- a/test/models/dao_contract_test.rb +++ b/test/models/dao_contract_test.rb @@ -17,9 +17,6 @@ class DaoContractTest < ActiveSupport::TestCase should validate_presence_of(:depositors_count) should validate_numericality_of(:depositors_count). is_greater_than_or_equal_to(0) - should validate_presence_of(:total_depositors_count) - should validate_numericality_of(:total_depositors_count). - is_greater_than_or_equal_to(0) end test "should have correct columns" do diff --git a/test/services/charts/daily_statistic_generator_test.rb b/test/services/charts/daily_statistic_generator_test.rb index 13b04281e..6c8c0b7c9 100644 --- a/test/services/charts/daily_statistic_generator_test.rb +++ b/test/services/charts/daily_statistic_generator_test.rb @@ -100,11 +100,6 @@ class DailyStatisticGeneratorTest < ActiveSupport::TestCase assert_equal addresses_count_temp.to_s, addresses_count end - test "it should get daily_dao_withdraw" do - daily_dao_withdraw = Charts::DailyStatisticGenerator.new(@datetime).call.daily_dao_withdraw - assert_equal @daily_dao_withdraw, daily_dao_withdraw - end - test "it should get total_dao_deposit" do # 1. from scratch deposit_amount = DaoEvent.processed.deposit_to_dao.created_before(@ended_at).sum(:value) @@ -282,20 +277,6 @@ class DailyStatisticGeneratorTest < ActiveSupport::TestCase assert_equal uncle_rate_temp.to_s, uncle_rate end - test "it should get total_depositors_count" do - # 1. from scratch - is_from_scratch = true - total_depositors_count_temp = DaoEvent.processed.take_away_all_deposit.created_before(@ended_at).count - total_depositors_count = Charts::DailyStatisticGenerator.new(@datetime, - is_from_scratch).call.total_depositors_count - assert_equal total_depositors_count_temp.to_s, total_depositors_count - # 2. not from scratch - new_depositors_count_today = DaoEvent.processed.new_dao_depositor.created_after(@started_at).created_before(@ended_at).count - total_depositors_count_temp = new_depositors_count_today + @yesterday_daily_statistic.total_depositors_count.to_i - total_depositors_count = Charts::DailyStatisticGenerator.new(@datetime).call.total_depositors_count - assert_equal total_depositors_count_temp.to_s, total_depositors_count - end - test "it should get address_balance_distribution" do max_n = 9 ranges = @@ -349,30 +330,6 @@ class DailyStatisticGeneratorTest < ActiveSupport::TestCase assert_equal daily_dao_deposit_temp, daily_dao_deposit end - test "it should get daily_dao_depositors_count" do - daily_dao_depositors_count = Charts::DailyStatisticGenerator.new(@datetime).call.daily_dao_depositors_count - daily_dao_depositors_count_temp ||= DaoEvent.processed.new_dao_depositor.created_after(@started_at).created_before(@ended_at).count - assert_equal daily_dao_depositors_count_temp, daily_dao_depositors_count - end - - test "it should get dao_depositors_count" do - # 1. from scratch - is_from_scratch = true - create :dao_event_with_block, block: @block, ckb_transaction: @tx, event_type: :new_dao_depositor, - status: :processed, block_timestamp: @block.timestamp - total_depositors_count = Charts::DailyStatisticGenerator.new(@datetime, - is_from_scratch).call.total_depositors_count - dao_depositors_count_temp = total_depositors_count.to_i - DaoEvent.processed.take_away_all_deposit.created_before(@ended_at).count - dao_depositors_count = Charts::DailyStatisticGenerator.new(@datetime, is_from_scratch).call.dao_depositors_count - assert_equal dao_depositors_count_temp.to_s, dao_depositors_count - # 2. not from scratch - daily_dao_depositors_count = Charts::DailyStatisticGenerator.new(@datetime).call.daily_dao_depositors_count - withdrawals_today = DaoEvent.processed.take_away_all_deposit.created_after(@started_at).created_before(@ended_at).count - dao_depositors_count_temp = daily_dao_depositors_count.to_i - withdrawals_today + @yesterday_daily_statistic.dao_depositors_count.to_i - dao_depositors_count = Charts::DailyStatisticGenerator.new(@datetime).call.dao_depositors_count - assert_equal dao_depositors_count_temp.to_s, dao_depositors_count - end - test "it should get circulation_ratio" do total_dao_deposit = Charts::DailyStatisticGenerator.new(@datetime).call.total_dao_deposit circulating_supply = Charts::DailyStatisticGenerator.new(@datetime).call.circulating_supply diff --git a/test/test_helper.rb b/test/test_helper.rb index 3c9406b8c..037f48f7c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -410,18 +410,18 @@ def fake_dao_deposit_transaction(dao_cell_count, address) tx_hash: "0x#{SecureRandom.hex(32)}", block:, address:, - contained_dao_address_ids: [address.id], contained_address_ids: [address.id], tags: ["dao"]) + create(:dao_event, ckb_transaction_id: ckb_transaction1.id, address_id: address.id, event_type: "deposit_to_dao") create(:cell_output, ckb_transaction: ckb_transaction1, cell_index: number, tx_hash: "0x498315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block:, capacity: 10**8 * 1000, cell_type: "nervos_dao_deposit", address:) else ckb_transaction2 = create(:ckb_transaction, tx_hash: "0x#{SecureRandom.hex(32)}", block:, address:, - contained_dao_address_ids: [address.id], contained_address_ids: [address.id], tags: ["dao"]) + create(:dao_event, ckb_transaction_id: ckb_transaction2.id, address_id: address.id, event_type: "deposit_to_dao") create(:cell_output, ckb_transaction: ckb_transaction2, cell_index: number,