Skip to content

Commit

Permalink
Feat/fiber (#2301)
Browse files Browse the repository at this point in the history
* feat: synchronize peer and channel data in fiber network

* feat: add fiber coordinator

* chore: add foreign key fiber_peer_id

* chore: rename sent_tlc_balance column

* chore: refine fiber channel jbuilder attribute definitions

* feat: fiber peers paginate

* chore: change rpc_listening_addr type to array

* feat: sync fiber graph nodes and channels

* fix: set default page_size for fiber request

* feat: sync graph node udt config info

* chore: fiber udt cfg info add type_script

* refactor: fiber graph detect worker

* chore: add filter to fiber graph channels

* feat: add filter query to fiber graph node

* refactor: normalize query_key based on hex string detection

* feat: fiber graph channel add closed_transaction_info
  • Loading branch information
rabbitz authored Dec 5, 2024
1 parent 495503b commit 6c9ce5c
Show file tree
Hide file tree
Showing 52 changed files with 1,334 additions and 37 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@ BITCOIN_SIGNET_PASS=""

# Dynamic CORS configuration
PARTNER_DOMAINS="/localhost:\d*/"

# -------------------------------- Fiber segment --------------------------------
FIBER_NODE_URL=""
12 changes: 12 additions & 0 deletions app/controllers/api/v2/fiber/channels_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Api
module V2
module Fiber
class ChannelsController < BaseController
def show
@channel = FiberChannel.find_by(channel_id: params[:channel_id])
raise Api::V2::Exceptions::FiberChannelNotFoundError unless @channel
end
end
end
end
end
17 changes: 17 additions & 0 deletions app/controllers/api/v2/fiber/graph_channels_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Api
module V2
module Fiber
class GraphChannelsController < BaseController
def index
@page = params.fetch(:page, 1)
@page_size = params.fetch(:page_size, FiberPeer.default_per_page)
@channels = FiberGraphChannel.all
if params[:status] == "closed"
@channels = @channels.where.not(closed_transaction_id: nil)
end
@channels = @channels.page(@page).per(@page_size)
end
end
end
end
end
31 changes: 31 additions & 0 deletions app/controllers/api/v2/fiber/graph_nodes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Api
module V2
module Fiber
class GraphNodesController < BaseController
def index
@page = params.fetch(:page, 1)
@page_size = params.fetch(:page_size, FiberGraphNode.default_per_page)
@nodes =
if params[:q].present?
FiberGraphNode.where("alias = :q or peer_id = :q or node_id = :q", q: params[:q]).page(@page).per(@page_size)
else
FiberGraphNode.all.page(@page).per(@page_size)
end
end

def show
@node = FiberGraphNode.find_by(node_id: params[:node_id])
raise Api::V2::Exceptions::FiberGraphNodeNotFoundError unless @node

@graph_channels = FiberGraphChannel.where(node1: params[:node_id]).or(
FiberGraphChannel.where(node2: params[:node_id]),
)

if params[:status] == "closed"
@graph_channels = @graph_channels.where.not(closed_transaction_id: nil)
end
end
end
end
end
end
46 changes: 46 additions & 0 deletions app/controllers/api/v2/fiber/peers_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module Api
module V2
module Fiber
class PeersController < BaseController
before_action :test_connection, only: :create

def index
@page = params.fetch(:page, 1)
@page_size = params.fetch(:page_size, FiberPeer.default_per_page)
@peers = FiberPeer.all.page(@page).per(@page_size)
end

def show
@peer = FiberPeer.find_by(peer_id: params[:peer_id])
raise Api::V2::Exceptions::FiberPeerNotFoundError unless @peer
end

def create
fiber_peer = FiberPeer.find_or_initialize_by(peer_id: fiber_peer_params[:peer_id])
fiber_peer.name = fiber_peer_params[:name]
new_rpc = Array(fiber_peer_params[:rpc_listening_addr])
fiber_peer.rpc_listening_addr = (fiber_peer.rpc_listening_addr + new_rpc).uniq
fiber_peer.save!

FiberDetectWorker.perform_async(fiber_peer.peer_id)

head :no_content
rescue ActiveRecord::RecordInvalid => e
raise Api::V2::Exceptions::FiberPeerParamsInvalidError.new(e.message)
end

private

def fiber_peer_params
params.permit(:name, :peer_id, :rpc_listening_addr)
end

def test_connection
FiberCoordinator.instance.list_channels(fiber_peer_params[:rpc_listening_addr], { "peer_id": nil })
rescue StandardError => e
raise Api::V2::Exceptions::FiberPeerParamsInvalidError.new(e.message)
end
end
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/api/v2/portfolio/addresses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def create

head :no_content
rescue StandardError => e
raise Api::V2::Exceptions::SyncPortfolioAddressesError
raise Api::V2::Exceptions::ParamsInvalidError
end
end
end
Expand Down
30 changes: 27 additions & 3 deletions app/lib/api/v2/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ def initialize(detail)

class TokenCollectionNotFoundError < Error
def initialize
super(code: 2001, status: 404, title: "Token Collection Not Found", detail: "No token collection found by given script hash or id", href: "")
super(code: 2001, status: 404, title: "token collection not found", detail: "No token collection found by given script hash or id", href: "")
end
end

class AddressNotMatchEnvironmentError < Error
def initialize(ckb_net_mode)
super(code: 2022, status: 422, title: "Address is invalid", detail: "This address is not the #{ckb_net_mode} address", href: "")
super(code: 2022, status: 422, title: "address is invalid", detail: "This address is not the #{ckb_net_mode} address", href: "")
end
end

Expand Down Expand Up @@ -69,7 +69,31 @@ def initialize

class AddressNotFoundError < Error
def initialize
super code: 2009, status: 404, title: "Address Not Found", detail: "No address found by given address hash or lock hash", href: ""
super code: 2009, status: 404, title: "address not found", detail: "No address found by given address hash or lock hash", href: ""
end
end

class FiberPeerParamsInvalidError < Error
def initialize(detail)
super code: 2010, status: 404, title: "fiber peer params invalid", detail: , href: ""
end
end

class FiberPeerNotFoundError < Error
def initialize
super code: 2011, status: 404, title: "fiber peer not found", detail: "No peer found by given peer id", href: ""
end
end

class FiberChannelNotFoundError < Error
def initialize
super code: 2012, status: 404, title: "fiber channel not found", detail: "No channel found by given channel_id", href: ""
end
end

class FiberGraphNodeNotFoundError < Error
def initialize
super code: 2013, status: 404, title: "fiber graph node not found", detail: "No graph node found by given node id", href: ""
end
end
end
Expand Down
35 changes: 35 additions & 0 deletions app/models/fiber_channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class FiberChannel < ApplicationRecord
belongs_to :fiber_peer

def local_peer
fiber_peer || FiberPeer.new
end

def remote_peer
FiberPeer.find_by(peer_id:) || FiberPeer.new
end
end

# == Schema Information
#
# Table name: fiber_channels
#
# id :bigint not null, primary key
# peer_id :string
# channel_id :string
# state_name :string
# state_flags :string default([]), is an Array
# local_balance :decimal(64, 2) default(0.0)
# offered_tlc_balance :decimal(64, 2) default(0.0)
# remote_balance :decimal(64, 2) default(0.0)
# received_tlc_balance :decimal(64, 2) default(0.0)
# shutdown_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
# fiber_peer_id :integer
#
# Indexes
#
# index_fiber_channels_on_fiber_peer_id (fiber_peer_id)
# index_fiber_channels_on_peer_id_and_channel_id (peer_id,channel_id) UNIQUE
#
75 changes: 75 additions & 0 deletions app/models/fiber_graph_channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
class FiberGraphChannel < ApplicationRecord
MAX_PAGINATES_PER = 100
DEFAULT_PAGINATES_PER = 10
paginates_per DEFAULT_PAGINATES_PER
max_paginates_per MAX_PAGINATES_PER

belongs_to :udt, optional: true
belongs_to :open_transaction, class_name: "CkbTransaction"
belongs_to :closed_transaction, class_name: "CkbTransaction", optional: true

validates :open_transaction_id, presence: true

scope :open_channels, -> { where(closed_transaction_id: nil) }

def open_transaction_info
open_transaction.as_json(only: %i[tx_hash block_number block_timestamp]).merge(
{
capacity: funding_cell.capacity,
udt_amount: funding_cell.udt_amount,
address: funding_cell.address_hash,
},
)
end

def closed_transaction_info
return Hash.new unless closed_transaction

closed_transaction.as_json(only: %i[tx_hash block_number block_timestamp]).merge(
close_accounts: closed_transaction.outputs.map do |cell|
{
capacity: cell.capacity,
udt_amount: cell.udt_amount,
address: cell.address_hash,
}
end,
)
end

def udt_info
udt&.as_json(only: %i[full_name symbol decimal icon_file])
end

def funding_cell
open_transaction.outputs.includes(:lock_script).find_by(
lock_scripts: { code_hash: Settings.fiber_funding_code_hash },
)
end
end

# == Schema Information
#
# Table name: fiber_graph_channels
#
# id :bigint not null, primary key
# channel_outpoint :string
# funding_tx_block_number :bigint
# funding_tx_index :integer
# node1 :string
# node2 :string
# last_updated_timestamp :bigint
# created_timestamp :bigint
# node1_to_node2_fee_rate :decimal(30, ) default(0)
# node2_to_node1_fee_rate :decimal(30, ) default(0)
# capacity :decimal(64, 2) default(0.0)
# chain_hash :string
# created_at :datetime not null
# updated_at :datetime not null
# udt_id :bigint
# open_transaction_id :bigint
# closed_transaction_id :bigint
#
# Indexes
#
# index_fiber_graph_channels_on_channel_outpoint (channel_outpoint) UNIQUE
#
50 changes: 50 additions & 0 deletions app/models/fiber_graph_node.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
class FiberGraphNode < ApplicationRecord
MAX_PAGINATES_PER = 100
DEFAULT_PAGINATES_PER = 10
paginates_per DEFAULT_PAGINATES_PER
max_paginates_per MAX_PAGINATES_PER

has_many :fiber_udt_cfg_infos, dependent: :delete_all

def channel_links
FiberGraphChannel.where(node1: node_id).or(FiberGraphChannel.where(node2: node_id)).
where(closed_transaction_id: nil)
end

def udt_cfg_infos
fiber_udt_cfg_infos.map(&:udt_info)
end

def total_capacity
channel_links.sum(&:capacity)
end

def connected_node_ids
node_ids = channel_links.pluck(:node1, :node2).flatten
node_ids.uniq - [node_id]
end

def open_channels_count
channel_links.count
end
end

# == Schema Information
#
# Table name: fiber_graph_nodes
#
# id :bigint not null, primary key
# alias :string
# node_id :string
# addresses :string default([]), is an Array
# timestamp :bigint
# chain_hash :string
# auto_accept_min_ckb_funding_amount :decimal(30, )
# created_at :datetime not null
# updated_at :datetime not null
# peer_id :string
#
# Indexes
#
# index_fiber_graph_nodes_on_node_id (node_id) UNIQUE
#
38 changes: 38 additions & 0 deletions app/models/fiber_peer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class FiberPeer < ApplicationRecord
MAX_PAGINATES_PER = 100
DEFAULT_PAGINATES_PER = 10
paginates_per DEFAULT_PAGINATES_PER
max_paginates_per MAX_PAGINATES_PER

has_many :fiber_channels, dependent: :destroy

validates :peer_id, presence: true, uniqueness: true

def total_local_balance
fiber_channels.where(state_name: "CHANNEL_READY").sum(:local_balance)
end

def channels_count
fiber_channels.where(state_name: "CHANNEL_READY").count
end
end

# == Schema Information
#
# Table name: fiber_peers
#
# id :bigint not null, primary key
# name :string
# peer_id :string
# rpc_listening_addr :string default([]), is an Array
# first_channel_opened_at :datetime
# last_channel_updated_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
# node_id :string
# chain_hash :string
#
# Indexes
#
# index_fiber_peers_on_peer_id (peer_id) UNIQUE
#
16 changes: 16 additions & 0 deletions app/models/fiber_transaction.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class FiberTransaction < ApplicationRecord
belongs_to :fiber_channel
belongs_to :fiber_peer
end

# == Schema Information
#
# Table name: fiber_transactions
#
# id :bigint not null, primary key
# fiber_peer_id :integer
# fiber_channel_id :integer
# ckb_transaction_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
Loading

0 comments on commit 6c9ce5c

Please sign in to comment.