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

Deploy to testnet #1542

Merged
merged 2 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading