Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix conflict with testnet #1511

Merged
51 changes: 42 additions & 9 deletions app/controllers/api/v1/ckb_transactions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module Api
module V1
class CkbTransactionsController < ApplicationController
before_action :validate_query_params, only: :show
before_action :validate_pagination_params, :pagination_params,
only: :index
before_action :validate_query_params, only: [:show, :display_inputs, :display_outputs]
before_action :find_transaction, only: [:show, :display_inputs, :display_outputs]
before_action :validate_pagination_params, :pagination_params, only: [:index, :display_inputs, :display_outputs]

def index
if from_home_page?
Expand Down Expand Up @@ -103,17 +103,41 @@ def query
end

def show
ckb_transaction = CkbTransaction.where(tx_hash: params[:id]).order(tx_status: :desc).first
expires_in 10.seconds, public: true, must_revalidate: true

render json: CkbTransactionSerializer.new(@ckb_transaction)
end

raise Api::V1::Exceptions::CkbTransactionNotFoundError if ckb_transaction.blank?
def display_inputs
expires_in 1.hour, public: true, must_revalidate: true

if ckb_transaction.tx_status.to_s == "rejected" && ckb_transaction.detailed_message.blank?
PoolTransactionUpdateRejectReasonWorker.perform_async(ckb_transaction.tx_hash)
if @ckb_transaction.is_cellbase
cell_inputs = @ckb_transaction.cellbase_display_inputs
total_count = cell_inputs.count
else
cell_inputs = @ckb_transaction.cell_inputs.order(id: :asc).
page(@page).per(@page_size).fast_page
total_count = cell_inputs.total_count
cell_inputs = @ckb_transaction.normal_tx_display_inputs(cell_inputs)
end

expires_in 10.seconds, public: true, must_revalidate: true
render json: { data: cell_inputs, meta: { total: total_count, page_size: @page_size.to_i } }
end

def display_outputs
expires_in 1.hour, public: true, must_revalidate: true

render json: CkbTransactionSerializer.new(ckb_transaction)
if @ckb_transaction.is_cellbase
cell_outputs = @ckb_transaction.cellbase_display_outputs
total_count = cell_outputs.count
else
cell_outputs = @ckb_transaction.outputs.order(id: :asc).
page(@page).per(@page_size).fast_page
total_count = cell_outputs.total_count
cell_outputs = @ckb_transaction.normal_tx_display_outputs(cell_outputs)
end

render json: { data: cell_outputs, meta: { total: total_count, page_size: @page_size.to_i } }
end

private
Expand All @@ -140,6 +164,15 @@ def validate_query_params
render json: errors, status: status
end
end

def find_transaction
@ckb_transaction = CkbTransaction.where(tx_hash: params[:id]).order(tx_status: :desc).first
raise Api::V1::Exceptions::CkbTransactionNotFoundError if @ckb_transaction.blank?

if @ckb_transaction.tx_status.to_s == "rejected" && @ckb_transaction.detailed_message.blank?
PoolTransactionUpdateRejectReasonWorker.perform_async(@ckb_transaction.tx_hash)
end
end
end
end
end
48 changes: 23 additions & 25 deletions app/controllers/api/v2/pending_transactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,32 @@ class PendingTransactionsController < BaseController
before_action :set_page_and_page_size

def index
pending_transactions = CkbTransaction.tx_pending.includes(:cell_inputs).
where.not(cell_inputs: { previous_cell_output_id: nil, from_cell_base: false })
expires_in 10.seconds, public: true, must_revalidate: true, stale_while_revalidate: 5.seconds

if stale?(pending_transactions)
expires_in 10.seconds, public: true, must_revalidate: true, stale_while_revalidate: 5.seconds
tx_ids = CkbTransaction.tx_pending.ids
unique_tx_ids = CellInput.where(ckb_transaction_id: tx_ids).
where.not(previous_cell_output_id: nil, from_cell_base: false).
pluck(:ckb_transaction_id).uniq
pending_transactions = CkbTransaction.where(id: unique_tx_ids).
order(transactions_ordering).page(@page).per(@page_size)

total_count = pending_transactions.count
pending_transactions = sort_transactions(pending_transactions).
page(@page).per(@page_size)

json = {
data: pending_transactions.map do |tx|
{
transaction_hash: tx.tx_hash,
capacity_involved: tx.capacity_involved,
transaction_fee: tx.transaction_fee,
created_at: tx.created_at,
create_timestamp: (tx.created_at.to_f * 1000).to_i
}
end,
meta: {
total: total_count,
page_size: @page_size.to_i
json = {
data: pending_transactions.map do |tx|
{
transaction_hash: tx.tx_hash,
capacity_involved: tx.capacity_involved,
transaction_fee: tx.transaction_fee,
created_at: tx.created_at,
create_timestamp: (tx.created_at.to_f * 1000).to_i
}
end,
meta: {
total: pending_transactions.total_count,
page_size: @page_size.to_i
}
}

render json: json
end
render json: json
end

def count
Expand All @@ -47,7 +45,7 @@ def set_page_and_page_size
@page_size = params[:page_size] || CkbTransaction.default_per_page
end

def sort_transactions(records)
def transactions_ordering
sort, order = params.fetch(:sort, "id.desc").split(".", 2)
sort =
case sort
Expand All @@ -61,7 +59,7 @@ def sort_transactions(records)
order = "asc"
end

records.order("ckb_transactions.#{sort} #{order} NULLS LAST")
"#{sort} #{order} NULLS LAST"
end
end
end
Expand Down
6 changes: 2 additions & 4 deletions app/models/cell_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,8 @@ def self.find_by_pointer(tx_hash, index)
Rails.cache.fetch(["cell_output", tx_hash, index], skip_nil: true,
race_condition_ttl: 10.seconds,
expires_in: 1.day) do
tx_id =
Rails.cache.fetch(["tx_id", tx_hash], expires_in: 1.day) do
CkbTransaction.find_by_tx_hash(tx_hash)&.id
end
tx_id = CkbTransaction.tx_committed.find_by_tx_hash(tx_hash)&.id
Rails.logger.info("find_by_pointer: tx_hash: #{tx_hash}, index: #{index}, tx_id: #{tx_id}")
find_by(ckb_transaction_id: tx_id, cell_index: index.is_a?(String) ? index.hex : index) if tx_id
end
end
Expand Down
191 changes: 2 additions & 189 deletions app/models/ckb_transaction.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# A transaction in CKB is composed by several inputs and several outputs
# the inputs are the previous generated outputs
class CkbTransaction < ApplicationRecord
include DisplayCells

self.primary_key = :id
MAX_PAGINATES_PER = 100
DEFAULT_PAGINATES_PER = 10
Expand Down Expand Up @@ -194,22 +196,6 @@ def cell_deps
cell_dependencies.explicit.includes(:cell_output).to_a.map(&:to_raw)
end

def display_inputs(previews: false)
if is_cellbase
cellbase_display_inputs
else
normal_tx_display_inputs(previews)
end
end

def display_outputs(previews: false)
if is_cellbase
cellbase_display_outputs
else
normal_tx_display_outputs(previews)
end
end

def income(address)
outputs.where(address: address).sum(:capacity) - inputs.where(address: address).sum(:capacity)
end
Expand All @@ -224,10 +210,6 @@ def dao_transaction?
)).exists?
end

def cell_info
nil
end

def detailed_message
reject_reason&.message
end
Expand Down Expand Up @@ -263,175 +245,6 @@ def self.last_n_days_transaction_fee_rates(last_n_day)

private

def normal_tx_display_outputs(previews)
cell_outputs_for_display = outputs.sort_by(&:id)
if previews
cell_outputs_for_display = cell_outputs_for_display[0, 10]
end
cell_outputs_for_display.map do |output|
consumed_tx_hash = output.live? ? nil : output.consumed_by&.tx_hash
display_output = {
id: output.id,
capacity: output.capacity,
occupied_capacity: output.occupied_capacity,
address_hash: output.address_hash,
status: output.status,
consumed_tx_hash: consumed_tx_hash,
cell_type: output.cell_type
}
display_output.merge!(attributes_for_udt_cell(output)) if output.udt?
display_output.merge!(attributes_for_cota_registry_cell(output)) if output.cota_registry?
display_output.merge!(attributes_for_cota_regular_cell(output)) if output.cota_regular?

display_output.merge!(attributes_for_m_nft_cell(output)) if output.cell_type.in?(%w(
m_nft_issuer m_nft_class
m_nft_token
))
display_output.merge!(attributes_for_nrc_721_cell(output)) if output.cell_type.in?(%w(
nrc_721_token
nrc_721_factory
))

CkbUtils.hash_value_to_s(display_output)
end
end

def cellbase_display_outputs
cell_outputs_for_display = outputs.to_a.sort_by(&:id)
cellbase = Cellbase.new(block)
cell_outputs_for_display.map do |output|
consumed_tx_hash = output.live? ? nil : output.consumed_by.tx_hash
CkbUtils.hash_value_to_s(id: output.id, capacity: output.capacity, occupied_capacity: output.occupied_capacity, address_hash: output.address_hash,
target_block_number: cellbase.target_block_number, base_reward: cellbase.base_reward, commit_reward: cellbase.commit_reward, proposal_reward: cellbase.proposal_reward, secondary_reward: cellbase.secondary_reward, status: output.status, consumed_tx_hash: consumed_tx_hash)
end
end

def normal_tx_display_inputs(previews)
cell_inputs_for_display = cell_inputs.to_a.sort_by(&:id)
if previews
cell_inputs_for_display = cell_inputs_for_display[0, 10]
end
cell_inputs_for_display.each_with_index.map do |cell_input, index|
previous_cell_output = cell_input.previous_cell_output
unless previous_cell_output
next({
from_cellbase: false,
capacity: "",
occupied_capacity: "",
address_hash: "",
generated_tx_hash: cell_input.previous_tx_hash,
cell_index: cell_input.previous_index,
since: {
raw: hex_since(cell_input.since.to_i),
median_timestamp: cell_input.block&.median_timestamp.to_i
}
})
end

display_input = {
id: previous_cell_output.id,
from_cellbase: false,
capacity: previous_cell_output.capacity,
occupied_capacity: previous_cell_output.occupied_capacity,
address_hash: previous_cell_output.address_hash,
generated_tx_hash: previous_cell_output.ckb_transaction.tx_hash,
cell_index: previous_cell_output.cell_index,
cell_type: previous_cell_output.cell_type,
since: {
raw: hex_since(cell_input.since.to_i),
median_timestamp: cell_input.block&.median_timestamp.to_i
}
}
display_input.merge!(attributes_for_dao_input(previous_cell_output)) if previous_cell_output.nervos_dao_withdrawing?
if previous_cell_output.nervos_dao_deposit?
display_input.merge!(attributes_for_dao_input(cell_outputs[index],
false))
end
display_input.merge!(attributes_for_udt_cell(previous_cell_output)) if previous_cell_output.udt?
display_input.merge!(attributes_for_m_nft_cell(previous_cell_output)) if previous_cell_output.cell_type.in?(%w(
m_nft_issuer m_nft_class m_nft_token
))
display_input.merge!(attributes_for_nrc_721_cell(previous_cell_output)) if previous_cell_output.cell_type.in?(%w(
nrc_721_token nrc_721_factory
))

CkbUtils.hash_value_to_s(display_input)
end
end

def hex_since(int_since_value)
return "0x#{int_since_value.to_s(16).rjust(16, '0')}"
end

def attributes_for_udt_cell(udt_cell)
info = CkbUtils.hash_value_to_s(udt_cell.udt_info)
{
udt_info: info,
extra_info: info
}
end

def attributes_for_m_nft_cell(m_nft_cell)
info = m_nft_cell.m_nft_info
{ m_nft_info: info, extra_info: info }
end

def attributes_for_cota_registry_cell(cota_cell)
info = cota_cell.cota_registry_info
{ cota_registry_info: info, extra_info: info }
end

def attributes_for_cota_regular_cell(cota_cell)
info = cota_cell.cota_regular_info
{ cota_regular_info: info, extra_info: info }
end

def attributes_for_nrc_721_cell(nrc_721_cell)
info = nrc_721_cell.nrc_721_nft_info
{ nrc_721_token_info: info, extra_info: info }
end

def attributes_for_dao_input(nervos_dao_withdrawing_cell, is_phase2 = true)
nervos_dao_withdrawing_cell_generated_tx = nervos_dao_withdrawing_cell.ckb_transaction
nervos_dao_deposit_cell = nervos_dao_withdrawing_cell_generated_tx.cell_inputs.order(:id)[nervos_dao_withdrawing_cell.cell_index].previous_cell_output
# start block: the block contains the trasaction which generated the deposit cell output
compensation_started_block = Block.select(:number, :timestamp).find(nervos_dao_deposit_cell.block.id)
# end block: the block contains the transaction which generated the withdrawing cell
compensation_ended_block = Block.select(:number, :timestamp).find(nervos_dao_withdrawing_cell_generated_tx.block_id)
interest = CkbUtils.dao_interest(nervos_dao_withdrawing_cell)

attributes = {
compensation_started_block_number: compensation_started_block.number,
compensation_started_timestamp: compensation_started_block.timestamp,
compensation_ended_block_number: compensation_ended_block.number,
compensation_ended_timestamp: compensation_ended_block.timestamp,
interest: interest
}

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
end

CkbUtils.hash_value_to_s(attributes)
end

def cellbase_display_inputs
cellbase = Cellbase.new(block)
[
CkbUtils.hash_value_to_s(
id: nil,
from_cellbase: true,
capacity: nil,
occupied_capacity: nil,
address_hash: nil,
target_block_number: cellbase.target_block_number,
generated_tx_hash: tx_hash
)
]
end

def recover_dead_cell
inputs.update_all(status: "live", consumed_by_id: nil, consumed_block_timestamp: nil)
end
Expand Down
Empty file removed app/models/concerns/.keep
Empty file.
Loading