-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add bitcoin address mapping (#1679)
* feat: add bitcoin address mapping * refactor: address transactions * refactor: search pending transactions with bitcoin address * chore: fix rgb transaction attribute
- Loading branch information
Showing
18 changed files
with
364 additions
and
219 deletions.
There are no files selected for viewing
77 changes: 6 additions & 71 deletions
77
app/controllers/api/v1/address_pending_transactions_controller.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1,29 @@ | ||
module Api | ||
module V1 | ||
class AddressTransactionsController < ApplicationController | ||
before_action :validate_query_params | ||
before_action :validate_pagination_params, :pagination_params | ||
before_action :find_address, only: %i[show download_csv] | ||
before_action :validate_pagination_params | ||
|
||
def show | ||
expires_in 10.seconds, public: true, must_revalidate: true, stale_while_revalidate: 5.seconds | ||
|
||
order_by, asc_or_desc = account_books_ordering | ||
tx_ids = AccountBook.joins(:ckb_transaction). | ||
where(account_books: { address_id: @address.id }, | ||
ckb_transactions: { tx_status: "committed" }). | ||
order(order_by => asc_or_desc). | ||
page(@page).per(@page_size).fast_page | ||
|
||
total_count = AccountBook.where(address_id: @address.id).count | ||
total_count = tx_ids.total_count if total_count < 1_000 | ||
|
||
ckb_transaction_ids = tx_ids.map(&:ckb_transaction_id) | ||
ckb_transactions = CkbTransaction.where(id: ckb_transaction_ids). | ||
select(:id, :tx_hash, :block_id, :block_number, :block_timestamp, | ||
:is_cellbase, :updated_at, :capacity_involved, :created_at). | ||
order(order_by => asc_or_desc) | ||
|
||
options = FastJsonapi::PaginationMetaGenerator.new( | ||
request:, | ||
records: ckb_transactions, | ||
page: @page, | ||
page_size: @page_size, | ||
total_count:, | ||
).call | ||
ckb_transaction_serializer = CkbTransactionsSerializer.new( | ||
ckb_transactions, | ||
options.merge(params: { previews: true, address: @address }), | ||
json = Addresses::CkbTransactions.run!( | ||
{ request:, | ||
key: params[:id], sort: params[:sort], | ||
page: params[:page], page_size: params[:page_size] }, | ||
) | ||
|
||
json = | ||
if QueryKeyUtils.valid_address?(params[:id]) | ||
if @address.address_hash == @address.query_address | ||
ckb_transaction_serializer.serialized_json | ||
else | ||
ckb_transaction_serializer.serialized_json.gsub(@address.address_hash, @address.query_address) | ||
end | ||
else | ||
ckb_transaction_serializer.serialized_json | ||
end | ||
|
||
render json: | ||
end | ||
|
||
def download_csv | ||
address = Addresses::Explore.run!(key: params[:id]) | ||
raise Api::V1::Exceptions::AddressNotFoundError if address.is_a?(NullAddress) | ||
|
||
args = params.permit(:id, :start_date, :end_date, :start_number, :end_number, address_transaction: {}). | ||
merge(address_id: @address.id) | ||
merge(address_id: address.map(&:id)) | ||
file = CsvExportable::ExportAddressTransactionsJob.perform_now(args.to_h) | ||
|
||
send_data file, type: "text/csv; charset=utf-8; header=present", | ||
disposition: "attachment;filename=ckb_transactions.csv" | ||
end | ||
|
||
private | ||
|
||
def validate_query_params | ||
validator = Validations::Address.new(params) | ||
|
||
if validator.invalid? | ||
errors = validator.error_object[:errors] | ||
status = validator.error_object[:status] | ||
|
||
render json: errors, status: | ||
end | ||
end | ||
|
||
def pagination_params | ||
@page = params[:page] || 1 | ||
@page_size = params[:page_size] || CkbTransaction.default_per_page | ||
end | ||
|
||
def find_address | ||
@address = Address.find_address!(params[:id]) | ||
raise Api::V1::Exceptions::AddressNotFoundError if @address.is_a?(NullAddress) | ||
end | ||
|
||
def account_books_ordering | ||
sort, order = params.fetch(:sort, "ckb_transaction_id.desc").split(".", 2) | ||
sort = | ||
case sort | ||
when "time" then "ckb_transactions.block_timestamp" | ||
else "ckb_transactions.id" | ||
end | ||
|
||
if order.nil? || !order.match?(/^(asc|desc)$/i) | ||
order = "asc" | ||
end | ||
|
||
[sort, order] | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
module Addresses | ||
class CkbTransactions < ActiveInteraction::Base | ||
include Api::V1::Exceptions | ||
|
||
object :request, class: ActionDispatch::Request | ||
string :key, default: nil | ||
string :sort, default: "ckb_transaction_id.desc" | ||
integer :page, default: 1 | ||
integer :page_size, default: CkbTransaction.default_per_page | ||
|
||
def execute | ||
address = Explore.run!(key:) | ||
raise AddressNotFoundError if address.is_a?(NullAddress) | ||
|
||
address_id = address.map(&:id) | ||
|
||
order_by, asc_or_desc = account_books_ordering | ||
account_books = | ||
AccountBook.joins(:ckb_transaction). | ||
where(account_books: { address_id: }, | ||
ckb_transactions: { tx_status: "committed" }). | ||
order(order_by => asc_or_desc). | ||
page(page).per(page_size).fast_page | ||
|
||
ckb_transaction_ids = account_books.map(&:ckb_transaction_id) | ||
records = CkbTransaction.where(id: ckb_transaction_ids). | ||
select(select_fields). | ||
order(order_by => asc_or_desc) | ||
|
||
options = paginate_options(records, address_id) | ||
options.merge!(params: { previews: true, address: }) | ||
|
||
result = CkbTransactionsSerializer.new(records, options) | ||
wrap_result(result, address) | ||
end | ||
|
||
private | ||
|
||
def account_books_ordering | ||
sort_by, sort_order = sort.split(".", 2) | ||
sort_by = | ||
case sort_by | ||
when "time" then "ckb_transactions.block_timestamp" | ||
else "ckb_transactions.id" | ||
end | ||
|
||
if sort_order.nil? || !sort_order.match?(/^(asc|desc)$/i) | ||
sort_order = "asc" | ||
end | ||
|
||
[sort_by, sort_order] | ||
end | ||
|
||
def paginate_options(records, address_id) | ||
total_count = AccountBook.where(address_id:).count | ||
FastJsonapi::PaginationMetaGenerator.new( | ||
request:, records:, page:, page_size:, total_count:, | ||
).call | ||
end | ||
|
||
def select_fields | ||
%i[id tx_hash block_id block_number block_timestamp | ||
is_cellbase updated_at capacity_involved created_at] | ||
end | ||
|
||
# A lock script can correspond to multiple CKB addresses | ||
def wrap_result(result, address) | ||
if QueryKeyUtils.valid_address?(key) | ||
ckb_address = address[0] | ||
if ckb_address.address_hash == ckb_address.query_address | ||
result.serialized_json | ||
else | ||
result.serialized_json.gsub(ckb_address.address_hash, ckb_address.query_address) | ||
end | ||
else | ||
result.serialized_json | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
module Addresses | ||
class Explore < ActiveInteraction::Base | ||
string :key, default: nil | ||
|
||
def execute | ||
result = find_address | ||
result ? wrap_result(result) : NullAddress.new(key) | ||
end | ||
|
||
private | ||
|
||
def find_address | ||
return Address.find_by(lock_hash: key) if QueryKeyUtils.valid_hex?(key) | ||
return find_by_address_hash(key) if QueryKeyUtils.valid_address?(key) | ||
return find_by_bitcoin_address_hash(key) if BitcoinUtils.valid_address?(key) | ||
end | ||
|
||
def find_by_address_hash(key) | ||
lock_hash = CkbUtils.parse_address(key).script.compute_hash | ||
address = Address.find_by(lock_hash:) | ||
address.query_address = key if address | ||
address | ||
rescue StandardError | ||
nil | ||
end | ||
|
||
def find_by_bitcoin_address_hash(key) | ||
address_ids = BitcoinAddressMapping.includes(:bitcoin_address). | ||
where(bitcoin_address: { address_hash: key }).pluck(:address_id) | ||
Address.where(id: address_ids) | ||
end | ||
|
||
def wrap_result(result) | ||
result.is_a?(Array) ? result : [result] | ||
end | ||
end | ||
end |
Oops, something went wrong.