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

Feat/rgb #1843

Merged
merged 1 commit into from
May 13, 2024
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ FROM ruby:${RUBY_VERSION}-slim
# RUN sed --in-place --regexp-extended "s/(\/\/)(deb|security).debian.org/\1mirrors.ustc.edu.cn/" /etc/apt/sources.list && \
# apt-get update && apt-get upgrade --yes
RUN apt-get update && apt-get install -y \
libpq5 libsodium23 \
libpq5 libsodium23 curl \
libcurl4 libjemalloc2 \
&& rm -rf /var/lib/apt/lists/*
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v2/rgb_transactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Api
module V2
class RgbTransactionsController < BaseController
def index
@ckb_transactions = RgbTransactions::Index.run!(transaction_params)
@bitcoin_annotations = RgbTransactions::Index.run!(transaction_params)
end

private
Expand Down
22 changes: 6 additions & 16 deletions app/interactions/rgb_transactions/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,14 @@ class Index < ActiveInteraction::Base

def execute
order_by, asc_or_desc = transaction_ordering
transactions = CkbTransaction.where("tags @> array[?]::varchar[]", ["rgbpp"]).
order(order_by => asc_or_desc)
annotations = BitcoinAnnotation.includes(:ckb_transaction).
where("bitcoin_annotations.tags @> array[?]::varchar[]", ["rgbpp"])

if leap_direction.present?
transactions = transactions.where(
"CASE
WHEN (SELECT COUNT(*) FROM bitcoin_vins WHERE ckb_transaction_id = ckb_transactions.id) <
(SELECT COUNT(*) FROM bitcoin_vouts WHERE ckb_transaction_id = ckb_transactions.id AND op_return = false)
THEN 'in'
WHEN (SELECT COUNT(*) FROM bitcoin_vins WHERE ckb_transaction_id = ckb_transactions.id) >
(SELECT COUNT(*) FROM bitcoin_vouts WHERE ckb_transaction_id = ckb_transactions.id AND op_return = false)
THEN 'out'
ELSE 'equal'
END = ?", leap_direction
)
annotations = annotations.where("bitcoin_annotations.leap_direction = ?", leap_direction)
end

transactions.page(page).per(page_size)
annotations.page(page).per(page_size)
end

private
Expand All @@ -34,9 +24,9 @@ def transaction_ordering
sort_by =
case sort_by
when "confirmation", "number"
"block_number"
"ckb_transactions.block_number"
when "time"
"block_timestamp"
"ckb_transactions.block_timestamp"
end

if sort_order.nil? || !sort_order.match?(/^(asc|desc)$/i)
Expand Down
23 changes: 23 additions & 0 deletions app/models/bitcoin_annotation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class BitcoinAnnotation < ApplicationRecord
belongs_to :ckb_transaction

enum :leap_direction, %i[in withinBTC]
enum :transfer_step, %i[isomorphic unlock]
end

# == Schema Information
#
# Table name: bitcoin_annotations
#
# id :bigint not null, primary key
# ckb_transaction_id :bigint
# leap_direction :integer
# transfer_step :integer
# tags :string default([]), is an Array
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_bitcoin_annotations_on_ckb_transaction_id (ckb_transaction_id) UNIQUE
#
2 changes: 1 addition & 1 deletion app/models/bitcoin_vout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def commitment
# address_id :bigint
# created_at :datetime not null
# updated_at :datetime not null
# status :integer default(0)
# status :integer default("bound")
# consumed_by_id :bigint
#
# Indexes
Expand Down
1 change: 1 addition & 0 deletions app/models/cell_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class CellOutput < ApplicationRecord
dependent: :delete_all
has_one :cell_datum, class_name: "CellDatum", dependent: :destroy_async
has_one :bitcoin_vout
has_one :bitcoin_transfer

accepts_nested_attributes_for :cell_datum
validates :capacity, presence: true,
Expand Down
39 changes: 10 additions & 29 deletions app/models/concerns/ckb_transactions/bitcoin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,32 @@ module Bitcoin
included do
has_many :bitcoin_vouts
has_many :bitcoin_vins
has_many :bitcoin_transfers
has_one :bitcoin_annotation

delegate :leap_direction, to: :bitcoin_annotation
delegate :transfer_step, to: :bitcoin_annotation

def rgb_transaction?
!!tags&.include?("rgbpp")
!!bitcoin_annotation&.tags&.include?("rgbpp")
end

def btc_time_transaction?
!!tags&.include?("btc_time")
!!bitcoin_annotation&.tags&.include?("btc_time")
end

def rgb_txid
if rgb_transaction?
txid = bitcoin_transaction&.txid
return txid if txid.present?
end

if btc_time_transaction?
btc_time_lock_cell =
inputs.includes(:lock_script).find_by(lock_scripts: { code_hash: CkbSync::Api.instance.btc_time_code_hash }) ||
outputs.includes(:lock_script).find_by(lock_scripts: { code_hash: CkbSync::Api.instance.btc_time_code_hash })
parsed_args = CkbUtils.parse_btc_time_lock_cell(btc_time_lock_cell.lock_script.args)
return parsed_args.txid
end

nil
end

def leap_direction
return unless rgb_transaction?
return if !rgb_transaction? && !btc_time_transaction?

return "in" if bitcoin_vins.count < bitcoin_vouts.without_op_return.count
return "out" if bitcoin_vins.count > bitcoin_vouts.without_op_return.count

nil
transfer = bitcoin_transfers.order(lock_type: :asc).first
transfer&.bitcoin_transaction&.txid
end

def rgb_cell_changes
return 0 unless rgb_transaction?

bitcoin_vouts.without_op_return.count - bitcoin_vins.count
end

def bitcoin_transaction
BitcoinTransaction.includes(:bitcoin_vouts).
find_by(bitcoin_vouts: { ckb_transaction_id: id })
end
end
end
end
9 changes: 6 additions & 3 deletions app/views/api/v2/rgb_transactions/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
json.data do
json.ckb_transactions @ckb_transactions do |tx|
json.ckb_transactions @bitcoin_annotations do |annotation|
tx = annotation.ckb_transaction

json.id tx.id
json.tx_hash tx.tx_hash
json.block_id tx.block_id
json.block_number tx.block_number
json.block_timestamp tx.block_timestamp
json.leap_direction tx.leap_direction
json.transfer_step tx.transfer_step
json.rgb_cell_changes tx.rgb_cell_changes
json.rgb_txid tx.rgb_txid
end
end
json.meta do
json.total @ckb_transactions.total_count
json.page_size @ckb_transactions.current_per_page
json.total @bitcoin_annotations.total_count
json.page_size @bitcoin_annotations.current_per_page
end
51 changes: 43 additions & 8 deletions app/workers/bitcoin_transaction_detect_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def perform(number)
@rgbpp_cell_ids.each { ImportRgbppCellJob.perform_now(_1) }
# import btc time cells
@btc_time_cell_ids.each { ImportBtcTimeCellJob.perform_now(_1) }
# update tags
update_transaction_tags!
# update bitcoin annotation
build_bitcoin_annotations!
end
end

Expand Down Expand Up @@ -88,15 +88,50 @@ def cache_raw_transactions!
Rails.logger.error "cache raw transactions(#{@txids.uniq}) failed: #{e.message}"
end

def update_transaction_tags!
def build_bitcoin_annotations!
annotations = []

@block.ckb_transactions.each do |transaction|
transaction.tags ||= []
next unless BitcoinTransfer.exists?(ckb_transaction_id: transaction.id)

leap_direction, transfer_step = annotation_workflow_attributes(transaction)
tags = annotation_tags(transaction)
annotations << { ckb_transaction_id: transaction.id, leap_direction:, transfer_step:, tags: }
BitcoinAnnotation.upsert_all(annotations, unique_by: [:ckb_transaction_id]) if annotations.present?
end
end

def annotation_workflow_attributes(transaction)
sort_types = ->(lock_types) {
lock_types.sort! do |a, b|
if a && b
a <=> b
else
a ? -1 : 1
end
end
}

input_lock_types = transaction.input_cells.map { _1.bitcoin_transfer&.lock_type }.uniq
sort_types.call(input_lock_types)

cell_output_ids = transaction.input_cell_ids + transaction.cell_output_ids
lock_types = BitcoinTransfer.where(cell_output_id: cell_output_ids).pluck(:lock_type)
transaction.tags += lock_types.compact.uniq
output_lock_types = transaction.cell_outputs.map { _1.bitcoin_transfer&.lock_type }.uniq
sort_types.call(output_lock_types)

transaction.update!(tags: transaction.tags.uniq)
if input_lock_types == ["rgbpp"]
if output_lock_types == ["rgbpp"]
["withinBTC", "isomorphic"]
elsif [["btc_time", "rgbpp"], ["btc_time"]].include?(output_lock_types)
["in", "isomorphic"]
end
elsif input_lock_types == ["btc_time"]
["in", "unlock"]
end
end

def annotation_tags(transaction)
cell_output_ids = transaction.input_cell_ids + transaction.cell_output_ids
lock_types = BitcoinTransfer.where(cell_output_id: cell_output_ids).pluck(:lock_type)
lock_types.compact.uniq
end
end
14 changes: 14 additions & 0 deletions db/migrate/20240513055849_create_bitcoin_annotations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateBitcoinAnnotations < ActiveRecord::Migration[7.0]
def change
create_table :bitcoin_annotations do |t|
t.bigint :ckb_transaction_id
t.integer :leap_direction
t.integer :transfer_step
t.string :tags, default: [], array: true

t.timestamps
end

add_index :bitcoin_annotations, :ckb_transaction_id, unique: true
end
end
59 changes: 58 additions & 1 deletion db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,40 @@ CREATE SEQUENCE public.bitcoin_addresses_id_seq
ALTER SEQUENCE public.bitcoin_addresses_id_seq OWNED BY public.bitcoin_addresses.id;


--
-- Name: bitcoin_annotations; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.bitcoin_annotations (
id bigint NOT NULL,
ckb_transaction_id bigint,
leap_direction integer,
transfer_step integer,
tags character varying[] DEFAULT '{}'::character varying[],
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);


--
-- Name: bitcoin_annotations_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--

CREATE SEQUENCE public.bitcoin_annotations_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;


--
-- Name: bitcoin_annotations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--

ALTER SEQUENCE public.bitcoin_annotations_id_seq OWNED BY public.bitcoin_annotations.id;


--
-- Name: bitcoin_statistics; Type: TABLE; Schema: public; Owner: -
--
Expand Down Expand Up @@ -2699,6 +2733,13 @@ ALTER TABLE ONLY public.bitcoin_address_mappings ALTER COLUMN id SET DEFAULT nex
ALTER TABLE ONLY public.bitcoin_addresses ALTER COLUMN id SET DEFAULT nextval('public.bitcoin_addresses_id_seq'::regclass);


--
-- Name: bitcoin_annotations id; Type: DEFAULT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.bitcoin_annotations ALTER COLUMN id SET DEFAULT nextval('public.bitcoin_annotations_id_seq'::regclass);


--
-- Name: bitcoin_statistics id; Type: DEFAULT; Schema: public; Owner: -
--
Expand Down Expand Up @@ -3097,6 +3138,14 @@ ALTER TABLE ONLY public.bitcoin_addresses
ADD CONSTRAINT bitcoin_addresses_pkey PRIMARY KEY (id);


--
-- Name: bitcoin_annotations bitcoin_annotations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.bitcoin_annotations
ADD CONSTRAINT bitcoin_annotations_pkey PRIMARY KEY (id);


--
-- Name: bitcoin_statistics bitcoin_statistics_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
Expand Down Expand Up @@ -3881,6 +3930,13 @@ CREATE UNIQUE INDEX index_average_block_time_by_hour_on_hour ON public.average_b
CREATE UNIQUE INDEX index_bitcoin_addresses_on_mapping ON public.bitcoin_address_mappings USING btree (bitcoin_address_id, ckb_address_id);


--
-- Name: index_bitcoin_annotations_on_ckb_transaction_id; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX index_bitcoin_annotations_on_ckb_transaction_id ON public.bitcoin_annotations USING btree (ckb_transaction_id);


--
-- Name: index_bitcoin_statistics_on_timestamp; Type: INDEX; Schema: public; Owner: -
--
Expand Down Expand Up @@ -5176,6 +5232,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20240428085020'),
('20240429102325'),
('20240507041552'),
('20240509074313');
('20240509074313'),
('20240513055849');


5 changes: 5 additions & 0 deletions test/factories/bitcoin_annotations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FactoryBot.define do
factory :bitcoin_annotation do

end
end
7 changes: 7 additions & 0 deletions test/models/bitcoin_annotation_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require "test_helper"

class BitcoinAnnotationTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
Loading