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/fiber #2301

Merged
merged 16 commits into from
Dec 5, 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
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
Loading