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 #1623

Merged
merged 8 commits into from
Feb 20, 2024
94 changes: 64 additions & 30 deletions app/controllers/concerns/cell_data_comparator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ def compare_cells(transaction)
udt_transfers = diff_udt_cells(inputs, outputs)
cota_nft_transfers = diff_cota_nft_cells(transaction, inputs, outputs)
normal_nft_transfers = diff_normal_nft_cells(inputs, outputs)
nft_class_transfers = diff_nft_capacities(inputs, outputs)
dao_transfers = diff_dao_capacities(inputs, outputs)

merged_transfers =
[normal_transfers, udt_transfers, cota_nft_transfers, normal_nft_transfers, nft_class_transfers].reduce do |acc, h|
[normal_transfers, udt_transfers, cota_nft_transfers, normal_nft_transfers, dao_transfers].reduce do |acc, h|
acc.merge(h) { |_, ov, nv| ov + nv }
end

Expand Down Expand Up @@ -73,6 +73,20 @@ def diff_udt_cells(inputs, outputs)
transfers
end

def diff_dao_capacities(inputs, outputs)
transfers = Hash.new { |h, k| h[k] = Array.new }
cell_types = %w(nervos_dao_deposit nervos_dao_withdrawing)
inputs = inputs.where(cell_type: cell_types).group(:address_id, :cell_type).sum(:capacity)
outputs = outputs.where(cell_type: cell_types).group(:address_id, :cell_type).sum(:capacity)

(inputs.keys | outputs.keys).each do |k|
capacity = outputs[k].to_f - inputs[k].to_f
transfers[k[0]] << CkbUtils.hash_value_to_s({ capacity:, cell_type: k[1] })
end

transfers
end

def diff_cota_nft_cells(transaction, inputs, outputs)
transfers = Hash.new { |h, k| h[k] = Array.new }
inputs = inputs.cota_regular.group(:address_id).sum(:capacity)
Expand All @@ -88,58 +102,78 @@ def diff_cota_nft_cells(transaction, inputs, outputs)

def diff_normal_nft_cells(inputs, outputs)
transfers = Hash.new { |h, k| h[k] = Array.new }
cell_types = %w(m_nft_token nrc_721_token spore_cell)
nft_infos = Hash.new { |h, k| h[k] = nil }
cell_types = %w(m_nft_token nrc_721_token spore_cell m_nft_issuer m_nft_class nrc_721_factory cota_registry spore_cluster)

process_nft = ->(c, h) {
process_nft = ->(c, h, o) {
k = [c.address_id, c.cell_type, c.type_hash]
h[k] ||= { capacity: 0.0, count: 0 }
h[k][:capacity] += c.capacity
h[k][:count] -= 1
h[k][:count] += o

unless nft_infos[c.type_hash]
nft_infos[c.type_hash] = nft_info(c)
end
}
inputs = inputs.where(cell_type: cell_types).each_with_object({}) { |c, h| process_nft.call(c, h) }
outputs = outputs.where(cell_type: cell_types).each_with_object({}) { |c, h| process_nft.call(c, h) }
inputs = inputs.where(cell_type: cell_types).each_with_object({}) { |c, h| process_nft.call(c, h, -1) }
outputs = outputs.where(cell_type: cell_types).each_with_object({}) { |c, h| process_nft.call(c, h, 1) }

(inputs.keys | outputs.keys).each do |k|
address_id, cell_type, type_hash = k
token_id, collection_name = token_info(type_hash)
input = inputs[k]
output = outputs[k]
capacity = output&.dig(:capacity).to_f - input&.dig(:capacity).to_f
count = output&.dig(:count).to_i + input&.dig(:count).to_i
transfers[address_id] << CkbUtils.hash_value_to_s({ capacity:, cell_type:, token_id:, collection_name:, count: })
transfer = { capacity:, cell_type:, count: }
transfer.merge!(nft_infos[type_hash]) if nft_infos[type_hash]
transfers[address_id] << CkbUtils.hash_value_to_s(transfer)
end

transfers
end

def diff_nft_capacities(inputs, outputs)
transfers = Hash.new { |h, k| h[k] = Array.new }
cell_types = %w(m_nft_issuer m_nft_class nrc_721_factory cota_registry spore_cluster)
inputs = inputs.where(cell_type: cell_types).group(:address_id, :cell_type).sum(:capacity)
outputs = outputs.where(cell_type: cell_types).group(:address_id, :cell_type).sum(:capacity)

(inputs.keys | outputs.keys).each do |k|
capacity = outputs[k].to_f - inputs[k].to_f
transfers[k[0]] << CkbUtils.hash_value_to_s({ capacity:, cell_type: k[1] })
def nft_info(cell)
case cell.cell_type
when "m_nft_token", "nrc_721_token", "spore_cell"
item = TokenItem.joins(:type_script).where(type_script: { script_hash: cell.type_hash }).take
{ toekn_id: item&.token_id, name: item&.collection&.name }
when "m_nft_issuer"
{ name: CkbUtils.parse_issuer_data(cell.data).info["name"] }
when "m_nft_class"
{ name: CkbUtils.parse_token_class_data(cell.data).name }
when "nrc_721_factory"
type_script = cell.type_script
factory_cell = NrcFactoryCell.find_by(
code_hash: type_script.code_hash,
hash_type: type_script.hash_type,
args: type_script.args,
verified: true,
)
{ name: factory_cell&.name }
when "spore_cluster"
{ name: CkbUtils.parse_spore_cluster_data(cell.data)[:name] }
when "omiga_inscription_info"
type_script = cell.type_script
info = OmigaInscriptionInfo.find_by(
code_hash: type_script.code_hash,
hash_type: type_script.hash_type,
args: type_script.args,
)
{ name: info&.name }
end

transfers
end

def token_info(script_hash)
item = TokenItem.joins(:type_script).where(type_script: { script_hash: }).take
[item&.token_id, item&.collection&.name]
end

def cota_info(transaction, address_id)
info = Array.new
process_transfer = ->(item, count) {
collection = item.collection
info << CkbUtils.hash_value_to_s({
collection_name: collection.name,
count:,
token_id: item.token_id,
})
info << CkbUtils.hash_value_to_s(
{
name: collection.name,
count:,
token_id: item.token_id,
},
)
}

transaction.token_transfers.each do |t|
Expand Down
76 changes: 39 additions & 37 deletions app/jobs/import_transaction_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ def perform(tx_hash, extra_data = {})
CkbTransaction.write_raw_hash_cache tx_hash["hash"], tx_hash
tx_hash = tx_hash["hash"]
end
# raw = CkbTransaction.fetch_raw_hash(tx_hash)
@tx = CkbTransaction.unscoped.create_with(tx_status: :pending).find_or_create_by! tx_hash: tx_hash
@tx = CkbTransaction.unscoped.create_with(tx_status: :pending).find_or_create_by!(tx_hash:)
return unless tx.tx_pending?

Rails.logger.info "Importing #{tx.tx_hash}"
Expand Down Expand Up @@ -49,23 +48,23 @@ def perform(tx_hash, extra_data = {})
sdk_tx.inputs.each_with_index do |input, index|
if input.previous_output.tx_hash == CellOutput::SYSTEM_TX_HASH
tx.cell_inputs.create_with(
index: index
index:,
).create_or_find_by(
previous_cell_output_id: nil,
from_cell_base: true
from_cell_base: true,
)
else
cell = CellOutput.find_by(
tx_hash: input.previous_output.tx_hash,
cell_index: input.previous_output.index
cell_index: input.previous_output.index,
)

if cell
process_input tx.cell_inputs.create_with(
previous_cell_output_id: cell.id
previous_cell_output_id: cell.id,
).create_or_find_by!(
ckb_transaction_id: txid,
index: index
index:,
)
process_deployed_cell(cell.lock_script)
process_deployed_cell(cell.type_script) if cell.type_script
Expand All @@ -74,7 +73,8 @@ def perform(tx_hash, extra_data = {})
tx.cell_inputs.create_or_find_by!(
previous_tx_hash: input.previous_output.tx_hash,
previous_index: input.previous_output.index,
since: input.since
since: input.since,
index:,
)
puts "Missing input #{input.previous_output.to_h} in #{tx_hash}"
# cannot find corresponding cell output,
Expand All @@ -93,22 +93,24 @@ def perform(tx_hash, extra_data = {})
lock = LockScript.process(output.lock)
t = TypeScript.process(output.type) if output.type
cell = tx.cell_outputs.find_or_create_by(
tx_hash: tx_hash,
cell_index: index
tx_hash:,
cell_index: index,
)

# after the cell is created, create a datum
if output_data.present? && output_data != "0x"
(cell.cell_datum || cell.build_cell_datum).update(data: [output_data[2..]].pack("H*"))
end

cell.lock_script = lock
cell.type_script = t
cell.update!(
address_id: lock.address_id,
capacity: output.capacity,
occupied_capacity: cell.calculate_min_capacity,
status: "pending"
status: "pending",
)
puts "output cell created tx_hash: #{tx_hash}, index: #{index}, cell_id: #{cell.id}"
# after the cell is created, create a datum
if output_data.present? && output_data != "0x"
(cell.cell_datum || cell.build_cell_datum).update(data: [output_data[2..]].pack("H*"))
end

process_output cell
process_deployed_cell(cell.lock_script)
Expand Down Expand Up @@ -139,7 +141,7 @@ def parse_code_dep(cell_dep)
ckb_transaction_id: ckb_transaction.id,
# check if we already known the relationship between the contract cell and contract
contract_id: DeployedCell.cell_output_id_to_contract_id(cell_output.id),
implicit: cell_dep["implicit"] || false
implicit: cell_dep["implicit"] || false,
}

# we don't know how the cells in transaction may refer to the contract cell
Expand All @@ -165,13 +167,13 @@ def save_relationship
if cell_dependencies_attrs.present?
CellDependency.upsert_all cell_dependencies_attrs.uniq { |a|
a[:contract_cell_id]
}, unique_by: [:ckb_transaction_id, :contract_cell_id]
}, unique_by: %i[ckb_transaction_id contract_cell_id]
end
DeployedCell.upsert_all deployed_cells_attrs, unique_by: [:cell_output_id] if deployed_cells_attrs.present?
deployed_cells_attrs.each do |deployed_cell_attr|
DeployedCell.write_cell_output_id_to_contract_id(
deployed_cell_attr[:cell_output_id],
deployed_cell_attr[:contract_id]
deployed_cell_attr[:contract_id],
)
end
end
Expand All @@ -184,10 +186,10 @@ def process_deployed_cell(lock_script_or_type_script)

dep =
case lock_script_or_type_script.hash_type
when "data"
by_data_hash[lock_script_or_type_script.code_hash]
when "type"
by_type_hash[lock_script_or_type_script.code_hash]
when "data"
by_data_hash[lock_script_or_type_script.code_hash]
when "type"
by_type_hash[lock_script_or_type_script.code_hash]
end
return unless dep

Expand All @@ -204,7 +206,7 @@ def process_deployed_cell(lock_script_or_type_script)

deployed_cells_attrs << {
contract_id: contract.id,
cell_output_id: dep[:contract_cell_id]
cell_output_id: dep[:contract_cell_id],
}
end
end
Expand All @@ -229,7 +231,7 @@ def process_cell_dep(cell_dep)
dep_type: cell_dep["dep_type"],
ckb_transaction_id: ckb_transaction.id,
contract_id: nil,
implicit: false
implicit: false,
}
binary_data = mid_cell.binary_data
# binary_data = [hex_data[2..-1]].pack("H*")
Expand All @@ -244,10 +246,10 @@ def process_cell_dep(cell_dep)
parse_code_dep(
"out_point" => {
"tx_hash" => "0x#{tx_hash}",
"index" => cell_index
"index" => cell_index,
},
"dep_type" => "code",
"implicit" => true # this is an implicit dependency
"implicit" => true, # this is an implicit dependency
)
end
end
Expand All @@ -258,8 +260,8 @@ def process_header_deps
sdk_tx.header_deps.each_with_index do |header_dep, index|
header_deps_attrs << {
ckb_transaction_id: txid,
index: index,
header_hash: header_dep
index:,
header_hash: header_dep,
}
end
if header_deps_attrs.present?
Expand All @@ -274,7 +276,7 @@ def process_witnesses
witnesses_attrs << {
ckb_transaction_id: txid,
index: i,
data: w
data: w,
}
end
if witnesses_attrs.present?
Expand All @@ -291,7 +293,7 @@ def process_input(cell_input)
changes = address_changes[address_id] ||=
{
balance: 0,
balance_occupied: 0
balance_occupied: 0,
}
changes[:balance] -= cell_output.capacity
changes[:balance_occupied] -= cell_output.occupied_capacity if cell_output.occupied_capacity
Expand All @@ -304,7 +306,7 @@ def process_output(cell_output)
changes = address_changes[address_id] ||=
{
balance: 0,
balance_occupied: 0
balance_occupied: 0,
}
changes[:balance] += cell_output.capacity
changes[:balance_occupied] += cell_output.occupied_capacity
Expand All @@ -315,19 +317,19 @@ def save_changes
attrs =
address_changes.map do |address_id, c|
{
address_id: address_id,
address_id:,
ckb_transaction_id: txid,
changes: c
changes: c,
}
end
TransactionAddressChange.upsert_all(
attrs,
unique_by: [:address_id, :ckb_transaction_id],
unique_by: %i[address_id ckb_transaction_id],
on_duplicate: Arel.sql(
"changes = transaction_address_changes.changes || excluded.changes"
)
"changes = transaction_address_changes.changes || excluded.changes",
),
)
AccountBook.upsert_all address_changes.keys.map{|address_id| {ckb_transaction_id: tx.id, address_id:}}
AccountBook.upsert_all address_changes.keys.map { |address_id| { ckb_transaction_id: tx.id, address_id: } }
end
end
end
2 changes: 1 addition & 1 deletion app/models/cell_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def nrc_721_nft_info
type_hash:,
published: factory_cell&.verified,
display_name: factory_cell&.name,
nan: "",
uan: "",
}
when "nrc_721_token"
udt = Udt.find_by(type_hash:)
Expand Down
Loading
Loading