Skip to content

Commit

Permalink
Merge pull request #1497 from nervosnetwork/develop
Browse files Browse the repository at this point in the history
Deploy to testnet
  • Loading branch information
rabbitz authored Nov 18, 2023
2 parents 49ecfd4 + 321a7fc commit 88e2ac8
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 264 deletions.
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

0 comments on commit 88e2ac8

Please sign in to comment.