Skip to content

Commit

Permalink
fix: contract attrs may exist same deployed_cell_output_id but differ…
Browse files Browse the repository at this point in the history
…ent role

Signed-off-by: Miles Zhang <[email protected]>
  • Loading branch information
zmcNotafraid committed Dec 13, 2024
1 parent fb7293a commit 2b86ff6
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 140 deletions.
217 changes: 140 additions & 77 deletions app/workers/analyze_contract_from_cell_dependency_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,96 +8,159 @@ def perform
cell_deps_out_points_attrs = Set.new
contract_attrs = Set.new
cell_deps_attrs = Set.new
contract_roles = Hash.new { |hash, key| hash[key] = {} }

Check warning on line 11 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L11

Added line #L11 was not covered by tests

# 加载未分析的依赖数据
dependencies = load_unanalyzed_dependencies

Check warning on line 14 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L14

Added line #L14 was not covered by tests

# 按事务分组并逐组处理
dependencies.each do |ckb_transaction_id, cell_deps|
ckb_transaction = CkbTransaction.find(ckb_transaction_id)
lock_scripts, type_scripts = analyze_scripts(ckb_transaction)

Check warning on line 19 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L17-L19

Added lines #L17 - L19 were not covered by tests

process_cell_dependencies(
cell_deps,
lock_scripts,
type_scripts,
cell_deps_out_points_attrs,
contract_attrs,
cell_deps_attrs,
contract_roles,
)
end

Check warning on line 30 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L21-L30

Added lines #L21 - L30 were not covered by tests

CellDependency.where(contract_analyzed: false).where.not(block_number: nil).order("block_number desc").limit(1000).each do |cell_dep|
cell_deps_attrs << { contract_analyzed: true, ckb_transaction_id: cell_dep.ckb_transaction_id, contract_cell_id: cell_dep.contract_cell_id, dep_type: cell_dep.dep_type }
# 持久化数据
save_cell_deps_out_points(cell_deps_out_points_attrs)
save_contracts(contract_attrs, contract_roles)
save_cell_dependencies(cell_deps_attrs)
end

Check warning on line 36 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L33-L36

Added lines #L33 - L36 were not covered by tests

next if CellDepsOutPoint.where(contract_cell_id: cell_dep.contract_cell_id).exists?
private

Check warning on line 38 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L38

Added line #L38 was not covered by tests

ckb_transaction = CkbTransaction.find(cell_dep.ckb_transaction_id)
# 加载未分析的依赖数据
def load_unanalyzed_dependencies
CellDependency.where(contract_analyzed: false).
where.not(block_number: nil).
order("block_number desc").
limit(200).
group_by(&:ckb_transaction_id)
end

Check warning on line 47 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L41-L47

Added lines #L41 - L47 were not covered by tests

type_script_hashes = Set.new
lock_script_hashes = Set.new
# 分析脚本
def analyze_scripts(ckb_transaction)
lock_scripts = {}
type_scripts = {}

Check warning on line 52 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L50-L52

Added lines #L50 - L52 were not covered by tests

cell_outputs = ckb_transaction.cell_outputs.includes(:type_script, :lock_script).to_a
cell_inputs = ckb_transaction.cell_inputs.includes(:previous_cell_output).map(&:previous_cell_output)
cell_inputs.each do |input|
lock_script_hashes << input.lock_script.code_hash
type_script_hashes << input.type_script.code_hash if input.type_script
end
cell_outputs = ckb_transaction.cell_outputs.includes(:type_script).to_a
cell_inputs = ckb_transaction.cell_inputs.includes(:previous_cell_output).map(&:previous_cell_output)

Check warning on line 55 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L54-L55

Added lines #L54 - L55 were not covered by tests

cell_outputs.each do |output|
lock_script_hashes << output.lock_script.code_hash
type_script_hashes << output.type_script.code_hash if output.type_script
(cell_inputs + cell_outputs).each do |cell|
lock_scripts[cell.lock_script.code_hash] = cell.lock_script.hash_type
if cell.type_script
type_scripts[cell.type_script.code_hash] = cell.type_script.hash_type

Check warning on line 60 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L57-L60

Added lines #L57 - L60 were not covered by tests
end
end

Check warning on line 62 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L62

Added line #L62 was not covered by tests

[lock_scripts, type_scripts]
end

Check warning on line 65 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L64-L65

Added lines #L64 - L65 were not covered by tests

# 处理每个依赖
def process_cell_dependencies(cell_deps, lock_scripts, type_scripts, out_points_attrs, contract_attrs, cell_deps_attrs, contract_roles)
cell_deps.each do |cell_dep|
cell_deps_attrs << {
contract_analyzed: true,
ckb_transaction_id: cell_dep.ckb_transaction_id,
contract_cell_id: cell_dep.contract_cell_id,
dep_type: cell_dep.dep_type,
}
next if Contract.joins(:cell_deps_out_points).where(cell_deps_out_points: { contract_cell_id: cell_dep.contract_cell_id }).exists?

Check warning on line 76 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L68-L76

Added lines #L68 - L76 were not covered by tests

case cell_dep.dep_type
when "code"
cell_output = cell_dep.cell_output
cell_deps_out_points_attrs << {
tx_hash: cell_output.tx_hash,
cell_index: cell_output.cell_index,
deployed_cell_output_id: cell_output.id,
contract_cell_id: cell_output.id,
}

is_lock_script = cell_output.type_script&.script_hash.in?(lock_script_hashes) || cell_output.data_hash.in?(lock_script_hashes)
is_type_script = cell_output.type_script&.script_hash.in?(type_script_hashes) || cell_output.data_hash.in?(type_script_hashes)

if is_lock_script || is_type_script
contract_attrs <<
{
type_hash: cell_output.type_script&.script_hash,
data_hash: cell_output.data_hash,
deployed_cell_output_id: cell_output.id,
is_type_script:,
is_lock_script:,
deployed_args: cell_output.type_script&.args,
}
end

process_code_dep(cell_dep, lock_scripts, type_scripts, out_points_attrs, contract_attrs, contract_roles)

Check warning on line 80 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L80

Added line #L80 was not covered by tests
when "dep_group"
# when the type of cell_dep is "dep_group", it means the cell specified by the `out_point` is a list of out points to the actual referred contract cells
mid_cell = cell_dep.cell_output

binary_data = mid_cell.binary_data
# parse the actual list of out points from the data field of the cell
out_points_count = binary_data[0, 4].unpack("L<")
# iterate over the out point list and append actual referred contract cells to cell dependencies_attrs
0.upto(out_points_count[0] - 1) do |i|
part_tx_hash, cell_index = binary_data[4 + i * 36, 36].unpack("H64L<")

tx_hash = "0x#{part_tx_hash}"
cell_output = CellOutput.find_by_pointer tx_hash, cell_index
cell_deps_out_points_attrs << {
tx_hash:,
cell_index:,
deployed_cell_output_id: cell_output.id,
contract_cell_id: mid_cell.id,
}

is_lock_script = cell_output.type_script&.script_hash.in?(lock_script_hashes) || cell_output.data_hash.in?(lock_script_hashes)
is_type_script = cell_output.type_script&.script_hash.in?(type_script_hashes) || cell_output.data_hash.in?(type_script_hashes)

if is_lock_script || is_type_script
contract_attrs <<
{
type_hash: cell_output.type_script&.script_hash,
data_hash: cell_output.data_hash,
deployed_cell_output_id: cell_output.id,
deployed_args: cell_output.type_script&.args,
is_type_script:,
is_lock_script:,
}
end
end
process_dep_group(cell_dep, lock_scripts, type_scripts, out_points_attrs, contract_attrs, contract_roles)

Check warning on line 82 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L82

Added line #L82 was not covered by tests
end
end
if cell_deps_out_points_attrs.any?
CellDepsOutPoint.upsert_all(cell_deps_out_points_attrs,
unique_by: %i[contract_cell_id deployed_cell_output_id])
end

Check warning on line 85 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L85

Added line #L85 was not covered by tests

# 处理 "code" 类型依赖
def process_code_dep(cell_dep, lock_scripts, type_scripts, out_points_attrs, contract_attrs, contract_roles)
cell_output = cell_dep.cell_output
out_points_attrs << {
tx_hash: cell_output.tx_hash,
cell_index: cell_output.cell_index,
deployed_cell_output_id: cell_output.id,
contract_cell_id: cell_output.id,
}

Check warning on line 95 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L88-L95

Added lines #L88 - L95 were not covered by tests

update_contract_roles(cell_output, lock_scripts, type_scripts, contract_roles)

Check warning on line 97 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L97

Added line #L97 was not covered by tests

if contract_roles[cell_output.id][:is_lock_script] || contract_roles[cell_output.id][:is_type_script]
contract_attrs << build_contract_attr(cell_output, lock_scripts, type_scripts)

Check warning on line 100 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L99-L100

Added lines #L99 - L100 were not covered by tests
end
Contract.upsert_all(contract_attrs, unique_by: %i[deployed_cell_output_id]) if contract_attrs.any?
CellDependency.upsert_all(cell_deps_attrs, unique_by: %i[ckb_transaction_id contract_cell_id dep_type], update_only: :contract_analyzed)
end

Check warning on line 102 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L102

Added line #L102 was not covered by tests

# 处理 "dep_group" 类型依赖
def process_dep_group(cell_dep, lock_scripts, type_scripts, out_points_attrs, contract_attrs, contract_roles)
mid_cell = cell_dep.cell_output
binary_data = mid_cell.binary_data
out_points_count = binary_data[0, 4].unpack1("L<")

Check warning on line 108 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L105-L108

Added lines #L105 - L108 were not covered by tests

0.upto(out_points_count - 1) do |i|
part_tx_hash, cell_index = binary_data[4 + i * 36, 36].unpack("H64L<")
tx_hash = "0x#{part_tx_hash}"
cell_output = CellOutput.find_by_pointer(tx_hash, cell_index)

Check warning on line 113 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L110-L113

Added lines #L110 - L113 were not covered by tests

out_points_attrs << {
tx_hash:,
cell_index:,
deployed_cell_output_id: cell_output.id,
contract_cell_id: mid_cell.id,
}

Check warning on line 120 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L115-L120

Added lines #L115 - L120 were not covered by tests

update_contract_roles(cell_output, lock_scripts, type_scripts, contract_roles)

Check warning on line 122 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L122

Added line #L122 was not covered by tests

if contract_roles[cell_output.id][:is_lock_script] || contract_roles[cell_output.id][:is_type_script]
contract_attrs << build_contract_attr(cell_output, lock_scripts, type_scripts)
end
end
end

Check warning on line 128 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L124-L128

Added lines #L124 - L128 were not covered by tests

# 更新 contract_roles
def update_contract_roles(cell_output, lock_scripts, type_scripts, contract_roles)
is_lock_script = (lock_scripts[cell_output.data_hash] || lock_scripts[cell_output.type_script&.script_hash]).present?
is_type_script = (type_scripts[cell_output.data_hash] || type_scripts[cell_output.type_script&.script_hash]).present?
data_type = lock_scripts[cell_output.data_hash] || type_scripts[cell_output.data_hash]

Check warning on line 134 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L131-L134

Added lines #L131 - L134 were not covered by tests

contract_roles[cell_output.id][:is_lock_script] ||= is_lock_script
contract_roles[cell_output.id][:is_type_script] ||= is_type_script
contract_roles[cell_output.id][:hash_type] ||= data_type
end

Check warning on line 139 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L136-L139

Added lines #L136 - L139 were not covered by tests

# 构建单个合约属性
def build_contract_attr(cell_output, _lock_scripts, _type_scripts)
{
type_hash: cell_output.type_script&.script_hash,
data_hash: cell_output.data_hash,
deployed_cell_output_id: cell_output.id,
deployed_args: cell_output.type_script&.args,
}
end

Check warning on line 149 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L142-L149

Added lines #L142 - L149 were not covered by tests

# 保存数据
def save_cell_deps_out_points(attrs)
CellDepsOutPoint.upsert_all(attrs.to_a, unique_by: %i[contract_cell_id deployed_cell_output_id]) if attrs.any?
end

Check warning on line 154 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L152-L154

Added lines #L152 - L154 were not covered by tests

def save_contracts(attrs, roles)
return if attrs.empty?

Check warning on line 157 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L156-L157

Added lines #L156 - L157 were not covered by tests

new_attrs = attrs.map { |attr| attr.merge(roles[attr[:deployed_cell_output_id]]) }
Contract.upsert_all(new_attrs, unique_by: %i[deployed_cell_output_id])
end

Check warning on line 161 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L159-L161

Added lines #L159 - L161 were not covered by tests

def save_cell_dependencies(attrs)
CellDependency.upsert_all(attrs.to_a, unique_by: %i[ckb_transaction_id contract_cell_id dep_type], update_only: :contract_analyzed) if attrs.any?

Check warning on line 164 in app/workers/analyze_contract_from_cell_dependency_worker.rb

View check run for this annotation

Codecov / codecov/patch

app/workers/analyze_contract_from_cell_dependency_worker.rb#L163-L164

Added lines #L163 - L164 were not covered by tests
end
end
Loading

0 comments on commit 2b86ff6

Please sign in to comment.