Skip to content

Commit

Permalink
Merge pull request #1545 from nervosnetwork/testnet
Browse files Browse the repository at this point in the history
Deploy to mainnet
  • Loading branch information
zmcNotafraid authored Dec 29, 2023
2 parents c311576 + 6abe22e commit 7c006dc
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 205 deletions.
58 changes: 31 additions & 27 deletions app/controllers/api/v1/ckb_transactions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
module Api
module V1
class CkbTransactionsController < ApplicationController
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]
before_action :validate_query_params,
only: %i[show display_inputs display_outputs]
before_action :find_transaction,
only: %i[show display_inputs display_outputs]
before_action :validate_pagination_params, :pagination_params,
only: %i[index display_inputs display_outputs]

def index
if from_home_page?
Expand All @@ -15,7 +18,7 @@ def index
version: ckb_transactions.cache_version, race_condition_ttl: 3.seconds) do
CkbTransactionListSerializer.new(ckb_transactions).serialized_json
end
render json: json
render json:
else
ckb_transactions = CkbTransaction.tx_committed.normal.select(
:id, :tx_hash, :block_number, :block_timestamp, :live_cell_changes, :capacity_involved, :updated_at, :created_at
Expand All @@ -26,12 +29,12 @@ def index
order_by, asc_or_desc = params[:sort].split(".", 2)
order_by =
case order_by
when "height"
"block_number"
when "capacity"
"capacity_involved"
else
order_by
when "height"
"block_number"
when "capacity"
"capacity_involved"
else
order_by
end

head :not_found and return unless order_by.in? %w[
Expand All @@ -47,16 +50,16 @@ def index
version: ckb_transactions.cache_version, race_condition_ttl: 3.seconds) do
records_counter = RecordCounters::Transactions.new
options = FastJsonapi::PaginationMetaGenerator.new(
request: request,
request:,
records: ckb_transactions,
page: @page,
page_size: @page_size,
records_counter: records_counter
records_counter:,
).call
CkbTransactionListSerializer.new(ckb_transactions,
options).serialized_json
end
render json: json
render json:
end
end

Expand All @@ -72,11 +75,11 @@ def query
if @address
records_counter = @tx_ids =
AccountBook.where(
address_id: @address.id
address_id: @address.id,
).order(
"ckb_transaction_id" => :desc
"ckb_transaction_id" => :desc,
).select(
"ckb_transaction_id"
"ckb_transaction_id",
).page(@page).per(@page_size).fast_page
CkbTransaction.where(id: @tx_ids.map(&:ckb_transaction_id)).order(id: :desc)
else
Expand All @@ -89,17 +92,18 @@ def query
Rails.cache.realize(ckb_transactions.cache_key,
version: ckb_transactions.cache_version, race_condition_ttl: 1.minute) do
options = FastJsonapi::PaginationMetaGenerator.new(
request: request,
request:,
records: ckb_transactions,
page: @page,
page_size: @page_size,
records_counter: records_counter
records_counter:,
).call
CkbTransactionsSerializer.new(ckb_transactions,
options.merge(params: {
previews: true, address: @address })).serialized_json
previews: true, address: @address
})).serialized_json
end
render json: json
render json:
end

def show
Expand All @@ -121,7 +125,9 @@ def display_inputs
cell_inputs = @ckb_transaction.normal_tx_display_inputs(cell_inputs)
end

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

def display_outputs
Expand All @@ -137,7 +143,9 @@ def display_outputs
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 } }
render json: { data: cell_outputs,
meta: { total: total_count,
page_size: @page_size.to_i } }
end

private
Expand All @@ -161,17 +169,13 @@ def validate_query_params
errors = validator.error_object[:errors]
status = validator.error_object[:status]

render json: errors, status: status
render json: errors, 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
Expand Down
6 changes: 3 additions & 3 deletions app/models/ckb_sync/new_node_data_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1210,9 +1210,9 @@ def build_ckb_transactions!(node_block, local_block, inputs, outputs, outputs_da
end
# First update status thus we can use upsert later. otherwise, we may not be able to
# locate correct record according to tx_hash
binary_hashes = CkbUtils.hexes_to_bins(hashes)
pending_txs = CkbTransaction.where(tx_hash: binary_hashes, tx_status: :pending).pluck(:tx_hash, :created_at)
CkbTransaction.where(tx_hash: binary_hashes).update_all tx_status: "committed"
binary_hashes = CkbUtils.hexes_to_bins_sql(hashes)
pending_txs = CkbTransaction.where("tx_hash IN (#{binary_hashes})").where(tx_status: :pending).pluck(:tx_hash, :created_at)
CkbTransaction.where("tx_hash IN (#{binary_hashes})").update_all tx_status: "committed"

txs = CkbTransaction.upsert_all(ckb_transactions_attributes, unique_by: [:tx_status, :tx_hash],
returning: %w(id tx_hash block_timestamp created_at))
Expand Down
6 changes: 3 additions & 3 deletions app/utils/ckb_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,9 @@ def self.shannon_to_byte(shannon)
shannon / (10**8)
end

def self.hexes_to_bins(hashes)
if hashes.is_a?(Array) && hashes.length > 0
hashes.map { |h| [h[2..-1]].pack("H*") }
def self.hexes_to_bins_sql(hex_strings)
if hex_strings.is_a?(Array) && hex_strings.length > 0
hex_strings.map { |hex_string| ActiveRecord::Base.sanitize_sql_array(["E'\\\\x%s'::bytea", hex_string.delete_prefix("0x")]) }.join(", ")
else
[]
end
Expand Down
56 changes: 13 additions & 43 deletions app/workers/pool_transaction_check_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,25 @@ class PoolTransactionCheckWorker
sidekiq_options retry: 0

def perform
# Because iterating over all pool transaction entry record and get tx detail from CKB Node one by one
# will make heavy load to CKB node, slowing block processing, sometimes will lead to HTTP timeout
# So here we directly check the inputs and dependencies of the transaction locally in database
# If any of the input or dependency cells is used, the transaction will never be valid.
# Thus we can directly mark this transaction rejected without requesting to CKB Node.
# Only request the CKB Node for reject reason after we find the transaction is rejected.
pending_transactions = CkbTransaction.tx_pending.
includes(:cell_dependencies, cell_inputs: :previous_cell_output).
order(id: :asc).limit(150)
pending_transactions = CkbTransaction.tx_pending.where("created_at < ?",
2.minutes.ago)
pending_transactions.each do |tx|
is_rejected = false
rejected_transaction = nil
# check if any input is used by other transactions
tx.cell_inputs.each do |input|
if input.previous_cell_output && input.previous_cell_output.dead?
rejected_transaction = {
id: tx.id,
tx_status: "rejected",
created_at: tx.created_at,
updated_at: Time.current
}
is_rejected = true
break
response_string = CkbSync::Api.instance.directly_single_call_rpc method: "get_transaction",
params: [tx.tx_hash]
reason = response_string["result"]["tx_status"]
if reason["status"] == "rejected"
ApplicationRecord.transaction do
tx.update! tx_status: "rejected"
tx.create_reject_reason!(message: reason["reason"])
end
end

unless is_rejected
# check if any dependency cell(contract) is consumed by other transactions
tx.cell_dependencies.each do |dep|
if dep.cell_output && dep.cell_output.dead?
rejected_transaction = {
id: tx.id,
tx_status: "rejected",
created_at: tx.created_at,
updated_at: Time.current
}
is_rejected = true
break
end
if reason["status"] == "unknown"
ApplicationRecord.transaction do
tx.update! tx_status: "rejected"
tx.create_reject_reason!(message: "unknown")
end
end

if is_rejected
AfterCommitEverywhere.after_commit do
# fetch the reason from node
PoolTransactionUpdateRejectReasonWorker.perform_async tx.tx_hash
end
CkbTransaction.where(tx_hash: tx.tx_hash).update_all tx_status: :rejected # , detailed_message: reason
end
end
end
end
14 changes: 0 additions & 14 deletions app/workers/pool_transaction_update_reject_reason_worker.rb

This file was deleted.

6 changes: 3 additions & 3 deletions lib/scheduler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ def call_worker(clz)
call_worker AddressUnclaimedCompensationGenerator
end

# s.every "5m", overlap: false do
# call_worker PoolTransactionCheckWorker
# end
s.every "2m", overlap: false do
call_worker PoolTransactionCheckWorker
end

s.every "1h", overlap: false do
call_worker CleanUpWorker
Expand Down
22 changes: 12 additions & 10 deletions lib/tasks/migration/generate_referring_cells.rake
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ namespace :migration do
desc "Usage: RAILS_ENV=production bundle exec rake migration:generate_referring_cells"
task generate_referring_cells: :environment do
live_cells = CellOutput.live.left_joins(:referring_cell).where(referring_cells: { id: nil })
progress_bar = ProgressBar.create({ total: live_cells.count, format: "%e %B %p%% %c/%C" })
progress_bar = ProgressBar.create({ total: live_cells.count,
format: "%e %B %p%% %c/%C" })

live_cells.find_in_batches do |outputs|
outputs.each do |output|
progress_bar.increment

contracts = [output.lock_script.contract, output.type_script&.contract].compact
contracts = [output.lock_script.contract,
output.type_script&.contract].compact

next if contracts.empty?

contracts.each do |contract|
ReferringCell.create_or_find_by(
cell_output_id: output.id,
ckb_transaction_id: output.ckb_transaction_id,
contract_id: contract.id
contract_id: contract.id,
)
end
end
Expand All @@ -28,8 +30,8 @@ namespace :migration do
desc "Usage: RAILS_ENV=production bundle exec rake migration:generate_missed_type_script_contract_referring_cells"
task generate_missed_type_script_contract_referring_cells: :environment do
contract_hashes = Contract.where(role: "type_script").pluck(:code_hash)
binary_hashes = CkbUtils.hexes_to_bins(contract_hashes)
contract_type_ids = TypeScript.where(code_hash: binary_hashes).pluck(:id)
binary_hashes = CkbUtils.hexes_to_bins_sql(contract_hashes)
contract_type_ids = TypeScript.where("code_hash IN (#{binary_hashes})").pluck(:id)
contract_type_ids.each do |type_id|
puts "============#{type_id}"
live_cells = CellOutput.live.where(type_script_id: type_id)
Expand All @@ -38,11 +40,11 @@ namespace :migration do
outputs.each do |output|
contract = output.type_script&.contract

ReferringCell.create_or_find_by(
cell_output_id: output.id,
ckb_transaction_id: output.ckb_transaction_id,
contract_id: contract.id
)
ReferringCell.create_or_find_by(
cell_output_id: output.id,
ckb_transaction_id: output.ckb_transaction_id,
contract_id: contract.id,
)
end
end
end
Expand Down
11 changes: 0 additions & 11 deletions test/models/pending_transaction_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,4 @@ class PendingTransactionTest < ActiveSupport::TestCase
assert_equal %w(hash header_deps cell_deps inputs outputs outputs_data version witnesses).sort,
json.keys.map(&:to_s).sort
end

test "should update_detailed_message_for_rejected_transaction when detailed_message is nil" do
rejected_tx_id = "0xed2049c21ffccfcd26281d60f8f77ff117adb9df9d3f8cbe5fe86e893c66d359"
tx = create :pending_transaction, tx_status: :rejected, tx_hash: rejected_tx_id

VCR.use_cassette("get_rejected_transaction") do
PoolTransactionUpdateRejectReasonWorker.new.perform(rejected_tx_id)
end
tx.reload
assert tx.detailed_message.include?("Resolve failed Dead")
end
end
Loading

0 comments on commit 7c006dc

Please sign in to comment.