Skip to content

Commit

Permalink
Merge pull request #1791 from nervosnetwork/develop
Browse files Browse the repository at this point in the history
Deploy to testnet
  • Loading branch information
zmcNotafraid committed Apr 17, 2024
2 parents 1cba925 + b731bd8 commit f7b3722
Show file tree
Hide file tree
Showing 18 changed files with 338 additions and 88 deletions.
17 changes: 1 addition & 16 deletions app/controllers/api/v1/suggest_queries_controller.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,13 @@
module Api
module V1
class SuggestQueriesController < ApplicationController
before_action :validate_query_params

def index
json_response = SuggestQuery.new(params[:q]).find!
json_response = SuggestQuery.new(params[:q], params[:filter_by]).find!

render json: json_response
rescue ActiveRecord::RecordNotFound
raise Api::V1::Exceptions::SuggestQueryResultNotFoundError
end

private

def validate_query_params
validator = Validations::SuggestQuery.new(params)

if validator.invalid?
errors = validator.error_object[:errors]
status = validator.error_object[:status]

render json: errors, status:
end
end
end
end
end
20 changes: 17 additions & 3 deletions app/controllers/api/v1/xudts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@ class XudtsController < ApplicationController
before_action :validate_pagination_params, :pagination_params, only: :index

def index
udts = Udt.xudt
scope = Udt.xudt.includes(:xudt_tag)

if stale?(udts)
if params[:symbol].present?
scope = scope.where("LOWER(symbol) = ?", params[:symbol].downcase)
end

if params[:tags].present?
tags = parse_tags
scope = scope.joins(:xudt_tag).where("xudt_tags.tags @> array[?]::varchar[]", tags).select("udts.*") unless tags.empty?
end

if stale?(scope)
expires_in 30.minutes, public: true, stale_while_revalidate: 10.minutes, stale_if_error: 10.minutes

udts = sort_udts(udts).page(@page).per(@page_size).fast_page
udts = sort_udts(scope).page(@page).per(@page_size).fast_page
options = FastJsonapi::PaginationMetaGenerator.new(
request:,
records: udts,
Expand Down Expand Up @@ -73,6 +82,11 @@ def sort_udts(records)

records.order("#{sort} #{order}")
end

def parse_tags
tags = params[:tags].split(",")
tags & XudtTag::VALID_TAGS
end
end
end
end
3 changes: 1 addition & 2 deletions app/models/ckb_sync/new_node_data_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,6 @@ def build_udts!(local_block, outputs, outputs_data)
unless Udt.where(type_hash:).exists?
nft_token_attr = { full_name: nil, icon_file: nil,
published: false, symbol: nil, decimal: nil, nrc_factory_cell_id: nil }
issuer_address = CkbUtils.generate_address(output.lock, CKB::Address::Version::CKB2021)
if cell_type == "m_nft_token"
m_nft_class_type = TypeScript.where(code_hash: CkbSync::Api.instance.token_class_script_code_hash,
args: output.type.args[0..49]).first
Expand Down Expand Up @@ -735,7 +734,7 @@ def build_udts!(local_block, outputs, outputs_data)
end
udts_attributes << {
type_hash:, udt_type: parsed_udt_type, block_timestamp: local_block.timestamp, args: output.type.args,
code_hash: output.type.code_hash, hash_type: output.type.hash_type, issuer_address:
code_hash: output.type.code_hash, hash_type: output.type.hash_type
}.merge(nft_token_attr)
end
end
Expand Down
94 changes: 68 additions & 26 deletions app/models/suggest_query.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
class SuggestQuery
def initialize(query_key)
attr_reader :query_key, :filter_by

def initialize(query_key, filter_by = nil)
@query_key = query_key
@filter_by = filter_by
end

def find!
find_record_by_query_key!
if filter_by.present? && filter_by.to_i.zero?
aggregate_query!
else
single_query!
end
end

private

attr_reader :query_key

def find_record_by_query_key!
def single_query!
result =
if QueryKeyUtils.integer_string?(query_key)
find_cached_block
elsif QueryKeyUtils.valid_hex?(query_key)
find_by_hex
res = query_methods.map(&:call).compact
return res.first if res.any?
elsif QueryKeyUtils.valid_address?(query_key)
find_cached_address
end
Expand All @@ -26,11 +30,51 @@ def find_record_by_query_key!
result
end

def find_cached_block
block = Block.cached_find(query_key)
raise Api::V1::Exceptions::BlockNotFoundError if block.blank?
def aggregate_query!
results = Hash.new { |h| h[:data] = Array.new }

# If query_key is all numbers, search block
if QueryKeyUtils.integer_string?(query_key) && (block = find_cached_block).present?
results[:data] << block.serializable_hash[:data]
return results
end

# If the string length is less than 2, the query result will be empty
raise ActiveRecord::RecordNotFound if query_key.length < 2

if QueryKeyUtils.valid_hex?(query_key)
query_methods.each { results[:data] << _1.call.serializable_hash[:data] if _1.call.present? }
end
if QueryKeyUtils.valid_address?(query_key) && (address = find_cached_address).present?
results[:data] << address.serializable_hash[:data]
end
if (udts = find_udts_by_name_or_symbol).present?
results[:data].concat(udts.serializable_hash[:data])
end
if (collections = find_nft_collections_by_name).present?
results[:data].concat(collections.serializable_hash[:data])
end

raise ActiveRecord::RecordNotFound if results.blank?

results
end

def query_methods
[
method(:find_cached_block),
method(:find_ckb_transaction_by_hash),
method(:find_address_by_lock_hash),
method(:find_udt_by_type_hash),
method(:find_type_script_by_type_id),
method(:find_type_script_by_code_hash),
method(:find_lock_script_by_code_hash),
method(:find_bitcoin_transaction_by_txid),
]
end

block
def find_cached_block
Block.cached_find(query_key)
end

def find_ckb_transaction_by_hash
Expand All @@ -45,9 +89,7 @@ def find_address_by_lock_hash

def find_cached_address
address = Address.cached_find(query_key)
raise Api::V1::Exceptions::AddressNotFoundError if address.blank?

AddressSerializer.new(address)
AddressSerializer.new(address) if address.present?
end

def find_udt_by_type_hash
Expand All @@ -70,20 +112,20 @@ def find_type_script_by_code_hash
TypeScriptSerializer.new(type_script) if type_script.present?
end

def find_by_hex
Block.cached_find(query_key) ||
find_ckb_transaction_by_hash ||
find_address_by_lock_hash ||
find_udt_by_type_hash ||
find_type_script_by_type_id ||
find_type_script_by_code_hash ||
find_lock_script_by_code_hash ||
find_bitcoin_transaction_by_txid
end

def find_bitcoin_transaction_by_txid
txid = query_key.delete_prefix(Settings.default_hash_prefix)
bitcoin_transaction = BitcoinTransaction.find_by(txid:)
BitcoinTransactionSerializer.new(bitcoin_transaction) if bitcoin_transaction
end

def find_udts_by_name_or_symbol
udts = Udt.where(udt_type: %i[sudt xudt omiga_inscription], published: true).
where("full_name LIKE :query_key OR symbol LIKE :query_key", query_key: "%#{query_key}%")
UdtSerializer.new(udts) if udts.present?
end

def find_nft_collections_by_name
token_collections = TokenCollection.where("name LIKE :query_key", query_key: "%#{query_key}%")
TokenCollectionSerializer.new(token_collections) if token_collections.present?
end
end
2 changes: 2 additions & 0 deletions app/models/udt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class Udt < ApplicationRecord
belongs_to :nrc_factory_cell, optional: true
has_one :udt_verification
has_one :omiga_inscription_info
has_one :xudt_tag

enum udt_type: { sudt: 0, m_nft_token: 1, nrc_721_token: 2, spore_cell: 3,
omiga_inscription: 4, xudt: 5 }
Expand All @@ -18,6 +19,7 @@ class Udt < ApplicationRecord
scope :query_by_name_or_symbl, ->(search) {
where("lower(full_name) LIKE ? or lower(symbol) LIKE ?", "%#{search}%", "%#{search}%")
}
scope :published_xudt, -> { where(udt_type: :xudt, published: true) }

attribute :code_hash, :ckb_hash

Expand Down
21 changes: 21 additions & 0 deletions app/models/xudt_tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class XudtTag < ApplicationRecord
belongs_to :udt

VALID_TAGS = ["invalid", "suspicious", "out-of-length-range", "rgbpp-compatible", "layer-1-asset", "supply-limited", "duplicate", "layer-2-asset", "supply-unlimited"]
end

# == Schema Information
#
# Table name: xudt_tags
#
# id :bigint not null, primary key
# udt_id :integer
# udt_type_hash :string
# tags :string default([]), is an Array
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_xudt_tags_on_udt_id (udt_id) UNIQUE
#
5 changes: 5 additions & 0 deletions app/serializers/token_collection_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class TokenCollectionSerializer
include FastJsonapi::ObjectSerializer

attributes :standard, :name, :description, :icon_url, :symbol
end
6 changes: 6 additions & 0 deletions app/serializers/udt_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,10 @@ class UdtSerializer
} do |object|
object.omiga_inscription_info.is_repeated_symbol
end

attribute :xudt_tags, if: Proc.new { |record, _params|
record.udt_type == "xudt" && record.published
} do |object|
object.xudt_tag&.tags
end
end
57 changes: 57 additions & 0 deletions app/workers/xudt_tag_worker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
class XudtTagWorker
include Sidekiq::Job

def perform
udts = Udt.published_xudt.left_joins(:xudt_tag).where(xudt_tag: { id: nil }).limit(100)
attrs =
udts.map do |udt|
tags = mark_tags(udt)
{ udt_id: udt.id, udt_type_hash: udt.type_hash, tags: }
end

XudtTag.upsert_all(attrs, unique_by: :udt_id, on_duplicate: :update, update_only: :tags)
end

def mark_tags(udt)
if invalid_char?(udt.symbol)
["invalid"]
elsif invisible_char?(udt.symbol)
["suspicious"]
elsif out_of_length?(udt.symbol)
["out-of-length-range"]
elsif first_xudt?(udt.symbol, udt.block_timestamp)
if rgbpp_lock?(udt.issuer_address)
["rgbpp-compatible", "layer-1-asset", "supply-limited"]
else
["rgbpp-compatible", "layer-2-asset", "supply-unlimited"]
end
elsif rgbpp_lock?(udt.issuer_address)
["duplicate", "layer-1-asset", "supply-limited"]
else
["duplicate", "layer-2-asset", "supply-unlimited"]
end
end

def invalid_char?(symbol)
!symbol.ascii_only?
end

def invisible_char?(symbol)
(symbol =~ /^[\x21-\x7E]+$/).nil?
end

def out_of_length?(symbol)
symbol.length > 5 || symbol.length < 4
end

def first_xudt?(symbol, block_timestamp)
!Udt.xudt.where("LOWER(symbol) = ?", symbol.downcase).where("block_timestamp < ?", block_timestamp).exists?
end

def rgbpp_lock?(issuer_address)
CkbUtils.parse_address(issuer_address).script.code_hash == Settings.rgbpp_code_hash
end

## TODO: current no this condition
def omni_lock_with_supply_mode?(issuer_address); end
end
13 changes: 13 additions & 0 deletions db/migrate/20240415080556_create_xudt_tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateXudtTags < ActiveRecord::Migration[7.0]
def change
create_table :xudt_tags do |t|
t.integer :udt_id
t.string :udt_type_hash
t.string "tags", default: [], array: true

t.timestamps
end

add_index :xudt_tags, :udt_id, unique: true
end
end
Loading

0 comments on commit f7b3722

Please sign in to comment.