diff --git a/app/controllers/api/v1/address_dao_transactions_controller.rb b/app/controllers/api/v1/address_dao_transactions_controller.rb index 4b3fe1c84..09e4b8762 100644 --- a/app/controllers/api/v1/address_dao_transactions_controller.rb +++ b/app/controllers/api/v1/address_dao_transactions_controller.rb @@ -8,7 +8,10 @@ def show address = Address.find_address!(params[:id]) raise Api::V1::Exceptions::AddressNotFoundError if address.is_a?(NullAddress) - includes = { :cell_inputs => {:previous_cell_output => {:type_script => [], :bitcoin_vout => [], :lock_script => [] }, :block => []}, :cell_outputs => {}, :bitcoin_annotation => [], :account_books => {} } + includes = { bitcoin_annotation: [], + cell_outputs: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} + ckb_dao_transactions = address.ckb_dao_transactions .includes(includes) .select(select_fields) diff --git a/app/controllers/api/v1/address_udt_transactions_controller.rb b/app/controllers/api/v1/address_udt_transactions_controller.rb index 3ebf23dbe..da53495bd 100644 --- a/app/controllers/api/v1/address_udt_transactions_controller.rb +++ b/app/controllers/api/v1/address_udt_transactions_controller.rb @@ -12,7 +12,10 @@ def show udt = Udt.find_by(type_hash: params[:type_hash], published: true) raise Api::V1::Exceptions::UdtNotFoundError if udt.blank? - includes = { :cell_inputs => {:previous_cell_output => {:type_script => [], :bitcoin_vout => [], :lock_script => [] }, :block => []}, :cell_outputs => {}, :bitcoin_annotation => [], :account_books => {} } + includes = { bitcoin_annotation: [], + cell_outputs: [:address, :deployed_contract, :udt_cell, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:udt_cell, :address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} + ckb_udt_transactions = address.ckb_udt_transactions(udt.id) .includes(includes) .select(select_fields) diff --git a/app/controllers/api/v1/block_transactions_controller.rb b/app/controllers/api/v1/block_transactions_controller.rb index c6f687826..820ef8b44 100644 --- a/app/controllers/api/v1/block_transactions_controller.rb +++ b/app/controllers/api/v1/block_transactions_controller.rb @@ -18,7 +18,9 @@ def show where(account_books: { address_id: address.id }) end - includes = { :cell_inputs => {:previous_cell_output => {:type_script => [], :bitcoin_vout => [], :lock_script => [] }, :block => []}, :cell_outputs => {}, :bitcoin_annotation => [], :account_books => {} } + includes = { bitcoin_annotation: [], + cell_outputs: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} if stale?(ckb_transactions) expires_in 10.seconds, public: true, must_revalidate: true, stale_while_revalidate: 5.seconds diff --git a/app/controllers/api/v1/ckb_transactions_controller.rb b/app/controllers/api/v1/ckb_transactions_controller.rb index 0d92b69a2..abb0b2fda 100644 --- a/app/controllers/api/v1/ckb_transactions_controller.rb +++ b/app/controllers/api/v1/ckb_transactions_controller.rb @@ -84,7 +84,10 @@ def query CkbTransaction.recent.normal.page(@page).per(@page_size).fast_page end - includes = { :cell_inputs => {:previous_cell_output => {:type_script => [], :bitcoin_vout => [], :lock_script => [] }, :block => []}, :cell_outputs => {}, :bitcoin_annotation => [], :account_books => {} } + includes = { bitcoin_annotation: [], + cell_outputs: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} + ckb_transactions = ckb_transactions.includes(includes).select(:id, :tx_hash, :block_id, :tags, :block_number, :block_timestamp, :is_cellbase, :updated_at, :created_at) json = @@ -139,7 +142,15 @@ def validate_query_params end def find_transaction - @ckb_transaction = CkbTransaction.where(tx_hash: params[:id]).order(tx_status: :asc).first + + includes = { bitcoin_annotation: [], + witnesses: [], + block: [:epoch_statistic], + cell_dependencies: [:cell_output, :contract], + cell_outputs: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} + + @ckb_transaction = CkbTransaction.includes(includes).where(tx_hash: params[:id]).first raise Api::V1::Exceptions::CkbTransactionNotFoundError if @ckb_transaction.blank? end end diff --git a/app/controllers/api/v1/contract_transactions_controller.rb b/app/controllers/api/v1/contract_transactions_controller.rb index a3db70d67..b66cec190 100644 --- a/app/controllers/api/v1/contract_transactions_controller.rb +++ b/app/controllers/api/v1/contract_transactions_controller.rb @@ -11,7 +11,7 @@ def show if stale?(dao_contract) expires_in 10.seconds, public: true, must_revalidate: true, stale_while_revalidate: 5.seconds - ckb_transactions = dao_contract.ckb_transactions.includes(:cell_inputs, :cell_outputs).tx_committed.order("ckb_transactions.block_timestamp desc nulls last, ckb_transactions.id desc") + ckb_transactions = dao_contract.ckb_transactions.tx_committed.order("ckb_transactions.block_timestamp desc nulls last, ckb_transactions.id desc") if params[:tx_hash].present? ckb_transactions = ckb_transactions.where(tx_hash: params[:tx_hash]) @@ -25,7 +25,9 @@ def show where(account_books: { address_id: address.id }) end - includes = { :cell_inputs => {:previous_cell_output => {:type_script => [], :bitcoin_vout => [], :lock_script => [] }, :block => []}, :cell_outputs => {}, :bitcoin_annotation => [], :account_books => {} } + includes = { bitcoin_annotation: [], + cell_outputs: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} ckb_transactions = ckb_transactions .includes(includes) diff --git a/app/interactions/addresses/ckb_transactions.rb b/app/interactions/addresses/ckb_transactions.rb index 347c49188..b4a17831b 100644 --- a/app/interactions/addresses/ckb_transactions.rb +++ b/app/interactions/addresses/ckb_transactions.rb @@ -37,8 +37,16 @@ def execute ckb_transaction_ids = account_books.map(&:ckb_transaction_id) - includes = { :cell_inputs => {:previous_cell_output => {:type_script => [], :bitcoin_vout => [], :lock_script => [] }, :block => []}, :cell_outputs => {}, :bitcoin_annotation => [], :account_books => {} } - includes[:bitcoin_transfers] = {} if is_bitcoin + includes = if is_bitcoin + { bitcoin_annotation: [], + bitcoin_transfers: [:bitcoin_transaction], + cell_outputs: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script, bitcoin_vout: [:bitcoin_address, :bitcoin_transaction]], + cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script, bitcoin_vout: [:bitcoin_address, :bitcoin_transaction]]]} + else + { bitcoin_annotation: [], + cell_outputs: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} + end records = CkbTransaction.where(id: ckb_transaction_ids) .includes(includes) diff --git a/app/interactions/addresses/live_cells.rb b/app/interactions/addresses/live_cells.rb index 9e4c45847..76b23245c 100644 --- a/app/interactions/addresses/live_cells.rb +++ b/app/interactions/addresses/live_cells.rb @@ -39,9 +39,9 @@ def fetch_cell_output_scope(address) scope = if bound_status vout_ids = BitcoinVout.where(address_id: address_ids, status: bound_status).pluck(:cell_output_id) - CellOutput.live.includes(:type_script, :lock_script).where(id: vout_ids) + CellOutput.live.includes(:type_script, :lock_script, :block).where(id: vout_ids) else - CellOutput.live.includes(:type_script, :lock_script).where(address_id: address_ids) + CellOutput.live.includes(:type_script, :lock_script, :block).where(address_id: address_ids) end tag.present? ? filter_by_tag(scope) : scope diff --git a/app/interactions/udts/ckb_transactions.rb b/app/interactions/udts/ckb_transactions.rb index 58bb9912e..82cdb2046 100644 --- a/app/interactions/udts/ckb_transactions.rb +++ b/app/interactions/udts/ckb_transactions.rb @@ -30,7 +30,9 @@ def execute where(account_books: { address_id: address.map(&:id) }).distinct end - includes = { :cell_inputs => {:previous_cell_output => {:type_script => [], :bitcoin_vout => [], :lock_script => [] }, :block => []}, :cell_outputs => {}, :bitcoin_annotation => [], :account_books => {} } + includes = { bitcoin_annotation: [], + cell_outputs: [:address, :deployed_contract, :udt_cell, :type_script, :bitcoin_vout, :lock_script], + cell_inputs: [:block, previous_cell_output: [:address, :udt_cell, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]} records = ckb_transactions .includes(includes) diff --git a/app/models/cell_dependency.rb b/app/models/cell_dependency.rb index d95f42747..1160e1e18 100644 --- a/app/models/cell_dependency.rb +++ b/app/models/cell_dependency.rb @@ -3,11 +3,11 @@ class CellDependency < ApplicationRecord belongs_to :cell_output, foreign_key: "contract_cell_id", class_name: "CellOutput" has_many :cell_deps_out_points, foreign_key: :contract_cell_id, primary_key: :contract_cell_id, class_name: "CellDepsOutPoint" has_many :contracts, foreign_key: :contract_cell_id, primary_key: :contract_cell_id, class_name: "Contract" + has_one :contract, -> { where(is_primary: true) }, foreign_key: :contract_cell_id, primary_key: :contract_cell_id, class_name: "Contract" enum :dep_type, %i[code dep_group] def to_raw - contract = contracts.primary.first script = if contract { diff --git a/app/models/cell_output.rb b/app/models/cell_output.rb index 8cd4a493e..8d3fe8656 100644 --- a/app/models/cell_output.rb +++ b/app/models/cell_output.rb @@ -49,6 +49,8 @@ class CellOutput < ApplicationRecord belongs_to :address belongs_to :lock_script belongs_to :type_script, optional: true + has_one :deployed_contract, foreign_key: :deployed_cell_output_id, class_name: "Contract" + belongs_to :udt_cell, ->(c) { where(published: true) }, foreign_key: :type_hash, class_name: 'Udt', optional: true has_many :cell_dependencies, foreign_key: :contract_cell_id, dependent: :delete_all diff --git a/app/models/concerns/cell_outputs/extra_info.rb b/app/models/concerns/cell_outputs/extra_info.rb index f104041ab..fbfcf5906 100644 --- a/app/models/concerns/cell_outputs/extra_info.rb +++ b/app/models/concerns/cell_outputs/extra_info.rb @@ -7,7 +7,7 @@ module ExtraInfo def udt_info return unless cell_type.in?(%w(udt xudt xudt_compatible ssri)) - udt_info = Udt.find_by(type_hash:, published: true) + udt_info = udt_cell CkbUtils.hash_value_to_s( symbol: udt_info&.symbol, amount: udt_amount, @@ -190,7 +190,7 @@ def rgb_info def tags tags = [] tags << "fiber" if lock_script.code_hash == Settings.fiber_funding_code_hash - tags << "deployment" if Contract.exists?(deployed_cell_output_id: id) + tags << "deployment" if deployed_contract tags << "multisig" if (lock_script.code_hash == Settings.multisig_code_hash && lock_script.hash_type == "data1") || (lock_script.code_hash == Settings.secp_multisig_cell_type_hash && lock_script.hash_type == "type") diff --git a/app/models/concerns/ckb_transactions/bitcoin.rb b/app/models/concerns/ckb_transactions/bitcoin.rb index 3d9d2708f..65b5fa334 100644 --- a/app/models/concerns/ckb_transactions/bitcoin.rb +++ b/app/models/concerns/ckb_transactions/bitcoin.rb @@ -23,7 +23,7 @@ def btc_time_transaction? def rgb_txid return if !rgb_transaction? && !btc_time_transaction? - transfer = bitcoin_transfers.order(lock_type: :asc).first + transfer = bitcoin_transfers.sort_by(&:lock_type).first transfer&.bitcoin_transaction&.txid end diff --git a/app/models/concerns/ckb_transactions/display_cells.rb b/app/models/concerns/ckb_transactions/display_cells.rb index 515b37919..5bdf1634c 100644 --- a/app/models/concerns/ckb_transactions/display_cells.rb +++ b/app/models/concerns/ckb_transactions/display_cells.rb @@ -104,7 +104,9 @@ def normal_tx_display_inputs(cell_inputs_for_display) display_input.merge!(attributes_for_dao_input(previous_cell_output)) end if previous_cell_output.nervos_dao_deposit? - display_input.merge!(attributes_for_dao_input(cell_outputs.sort_by(&:cell_index)[cell_input.index], false)) + nervos_dao_withdrawing_cell = cell_outputs.sort_by(&:cell_index)[cell_input.index] + compensation_started_block = cell_input.block + display_input.merge!(attributes_for_dao_input(nervos_dao_withdrawing_cell, compensation_started_block, false)) end if previous_cell_output.udt? display_input.merge!(attributes_for_udt_cell(previous_cell_output)) @@ -217,13 +219,15 @@ def attributes_for_omiga_inscription_cell(omiga_inscription_cell) { omiga_inscription_info: info, extra_info: info } end - def attributes_for_dao_input(nervos_dao_withdrawing_cell, is_phase2 = true) - block_number = CKB::Utils.hex_to_bin(nervos_dao_withdrawing_cell.data).unpack("Q<").pack("Q>").unpack1("H*").hex - # start block: the block contains the transaction which generated the deposit cell output - compensation_started_block = Block.select(:number, :timestamp).find_by_number(block_number) + def attributes_for_dao_input(nervos_dao_withdrawing_cell, compensation_started_block = nil, is_phase2 = true) + unless compensation_started_block + started_block_number = CKB::Utils.hex_to_bin(nervos_dao_withdrawing_cell.data).unpack("Q<").pack("Q>").unpack1("H*").hex + # start block: the block contains the transaction which generated the deposit cell output + compensation_started_block = Block.find_by_number(started_block_number) + end # end block: the block contains the transaction which generated the withdrawing cell - compensation_ended_block = Block.select(:number, :timestamp).find(nervos_dao_withdrawing_cell.block_id) - interest = CkbUtils.dao_interest(nervos_dao_withdrawing_cell) + compensation_ended_block = nervos_dao_withdrawing_cell.block + interest = CkbUtils.dao_interest(nervos_dao_withdrawing_cell, compensation_started_block.dao) attributes = { compensation_started_block_number: compensation_started_block.number, @@ -234,9 +238,8 @@ def attributes_for_dao_input(nervos_dao_withdrawing_cell, is_phase2 = true) } if is_phase2 - number, timestamp = Block.where(id: block_id).pick(:number, :timestamp) # locked_until_block - attributes[:locked_until_block_number] = number - attributes[:locked_until_block_timestamp] = timestamp + attributes[:locked_until_block_number] = block_number + attributes[:locked_until_block_timestamp] = block_timestamp end CkbUtils.hash_value_to_s(attributes) diff --git a/app/serializers/address_serializer.rb b/app/serializers/address_serializer.rb index e3f5c63f5..632088f17 100644 --- a/app/serializers/address_serializer.rb +++ b/app/serializers/address_serializer.rb @@ -37,7 +37,7 @@ class AddressSerializer end attribute :udt_accounts do |object| if object.udt_accounts.present? - object.udt_accounts.published.map do |udt_account| + object.udt_accounts.find_all{|u| u.published }.map do |udt_account| if udt_account.udt_type == "sudt" { symbol: udt_account.symbol, diff --git a/app/serializers/ckb_transaction_serializer.rb b/app/serializers/ckb_transaction_serializer.rb index e4e377fe8..3487aec22 100644 --- a/app/serializers/ckb_transaction_serializer.rb +++ b/app/serializers/ckb_transaction_serializer.rb @@ -7,11 +7,11 @@ class CkbTransactionSerializer attributes :is_cellbase, :tx_status attribute :witnesses do |o| - o.witnesses.order("index ASC")&.map(&:data) || [] + o.witnesses.sort_by(&:index)&.map(&:data) || [] end attribute :cell_deps do |o| - o.cell_dependencies.order("id asc").includes(:cell_output, :contracts).to_a.map(&:to_raw) + o.cell_dependencies.sort_by(&:id).map(&:to_raw) end attribute :header_deps do |o| diff --git a/app/utils/ckb_utils.rb b/app/utils/ckb_utils.rb index aa60e24e0..e4004b7e5 100644 --- a/app/utils/ckb_utils.rb +++ b/app/utils/ckb_utils.rb @@ -270,9 +270,11 @@ def self.dao_withdraw_tx_fee(ckb_transaction, tx_previous_outputs) tx_previous_outputs.sum(&:capacity) + interests - CellOutput.where(ckb_transaction: ckb_transaction["id"]).sum(:capacity) end - def self.dao_interest(nervos_dao_withdrawing_cell) - block_number = CKB::Utils.hex_to_bin(nervos_dao_withdrawing_cell.data).unpack("Q<").pack("Q>").unpack1("H*").hex - deposit_dao = Block.find_by_number(block_number).dao + def self.dao_interest(nervos_dao_withdrawing_cell, deposit_dao = nil) + unless deposit_dao + block_number = CKB::Utils.hex_to_bin(nervos_dao_withdrawing_cell.data).unpack("Q<").pack("Q>").unpack1("H*").hex + deposit_dao = Block.find_by_number(block_number).dao + end withdrawing_dao_cell_block_dao = nervos_dao_withdrawing_cell.dao DaoCompensationCalculator.new(nil, withdrawing_dao_cell_block_dao, nervos_dao_withdrawing_cell, deposit_dao).call diff --git a/test/controllers/api/v1/address_dao_transactions_controller_test.rb b/test/controllers/api/v1/address_dao_transactions_controller_test.rb index 06c518c74..4998d53c2 100644 --- a/test/controllers/api/v1/address_dao_transactions_controller_test.rb +++ b/test/controllers/api/v1/address_dao_transactions_controller_test.rb @@ -59,7 +59,7 @@ class AddressDaoTransactionsControllerTest < ActionDispatch::IntegrationTest address = create(:address, :with_transactions) fake_dao_deposit_transaction(3, address) ckb_dao_transactions = address.ckb_dao_transactions.recent.page(page).per(page_size) - + valid_get api_v1_address_dao_transaction_url(address.address_hash) options = FastJsonapi::PaginationMetaGenerator.new(request:, records: ckb_dao_transactions, page:, page_size:).call diff --git a/test/controllers/api/v1/addresses_controller_test.rb b/test/controllers/api/v1/addresses_controller_test.rb index 7d4991605..5a268483c 100644 --- a/test/controllers/api/v1/addresses_controller_test.rb +++ b/test/controllers/api/v1/addresses_controller_test.rb @@ -260,6 +260,7 @@ class AddressesControllerTest < ActionDispatch::IntegrationTest udt_account = create(:udt_account, symbol: udt.symbol, full_name: udt.full_name, decimal: udt.decimal, published: true, address:, udt_id: udt.id, udt_type: "omiga_inscription", type_hash: udt.type_hash, amount: info.mint_limit) address.query_address = address.address_hash + valid_get api_v1_address_url(address.address_hash) assert_equal [ { diff --git a/test/models/ckb_transaction_test.rb b/test/models/ckb_transaction_test.rb index e9d50afd2..52940126e 100644 --- a/test/models/ckb_transaction_test.rb +++ b/test/models/ckb_transaction_test.rb @@ -226,6 +226,8 @@ class CkbTransactionTest < ActiveSupport::TestCase compensation_ended_block_number compensation_started_timestamp compensation_ended_timestamp interest cell_type cell_index since locked_until_block_number locked_until_block_timestamp tags type_script ).sort + + ckb_transaction = CkbTransaction.includes(:bitcoin_annotation, :account_books, cell_outputs: [:address, :deployed_contract], cell_inputs: [:block, previous_cell_output: [:address, :deployed_contract, :type_script, :bitcoin_vout, :lock_script]]).find(ckb_transaction.id) display_inputs = ckb_transaction.display_inputs assert_equal expected_attributes, display_inputs.first.keys.sort assert_equal expected_display_input, display_inputs.first.sort @@ -277,9 +279,9 @@ class CkbTransactionTest < ActiveSupport::TestCase occupied_capacity: deposit_output_cell.occupied_capacity, address_hash: deposit_output_cell.address_hash, generated_tx_hash: deposit_output_cell.ckb_transaction.tx_hash, - compensation_started_block_number: started_block.number, + compensation_started_block_number: ckb_transaction.block_number, compensation_ended_block_number: ended_block.number, - compensation_started_timestamp: started_block.timestamp, + compensation_started_timestamp: ckb_transaction.block_timestamp, compensation_ended_timestamp: ended_block.timestamp, interest:, cell_type: deposit_output_cell.cell_type,