Skip to content

Commit

Permalink
feat: adapt new DAO (#452)
Browse files Browse the repository at this point in the history
feat: adapt new DAO
  • Loading branch information
shaojunda authored Nov 8, 2019
2 parents e5d73f8 + 31b3143 commit 82a5cbf
Show file tree
Hide file tree
Showing 32 changed files with 248 additions and 176 deletions.
2 changes: 1 addition & 1 deletion app/controllers/api/v1/contract_transactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ContractTransactionsController < ApplicationController
before_action :validate_pagination_params, :pagination_params

def show
raise Api::V1::Exceptions::ContractNotFoundError if params[:id] != "dao"
raise Api::V1::Exceptions::ContractNotFoundError if params[:id] != DaoContract::CONTRACT_NAME
dao_contract = DaoContract.default_contract
ckb_transactions = dao_contract.ckb_transactions.distinct.recent.page(@page).per(@page_size)
options = FastJsonapi::PaginationMetaGenerator.new(request: request, records: ckb_transactions, page: @page, page_size: @page_size).call
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/contracts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Api
module V1
class ContractsController < ApplicationController
def show
raise Api::V1::Exceptions::ContractNotFoundError if params[:id] != "dao"
raise Api::V1::Exceptions::ContractNotFoundError if params[:id] != DaoContract::CONTRACT_NAME

render json: DaoContractSerializer.new(DaoContract.default_contract)
end
Expand Down
8 changes: 4 additions & 4 deletions app/models/address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Address < ApplicationRecord
has_many :cell_outputs
has_many :account_books
has_many :ckb_transactions, through: :account_books
validates :balance, :cell_consumed, :ckb_transactions_count, :subsidy, :dao_deposit, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
validates :balance, :cell_consumed, :ckb_transactions_count, :interest, :dao_deposit, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true

after_commit :flush_cache

Expand All @@ -24,7 +24,7 @@ def self.find_address!(query_key)
end

def self.cached_find(query_key)
Rails.cache.fetch([name, query_key], race_condition_ttl: 3.seconds) do
Rails.cache.realize([name, query_key], race_condition_ttl: 3.seconds) do
if QueryKeyUtils.valid_hex?(query_key)
find_by(lock_hash: query_key)
else
Expand All @@ -34,7 +34,7 @@ def self.cached_find(query_key)
end

def cached_lock_script
Rails.cache.fetch([self.class.name, "lock_script", lock_hash], race_condition_ttl: 3.seconds) do
Rails.cache.realize([self.class.name, "lock_script", lock_hash], race_condition_ttl: 3.seconds) do
lock_script.to_node_lock
end
end
Expand All @@ -59,7 +59,7 @@ def flush_cache
# lock_hash :binary
# pending_reward_blocks_count :integer default(0)
# dao_deposit :decimal(30, ) default(0)
# subsidy :decimal(30, ) default(0)
# interest :decimal(30, ) default(0)
#
# Indexes
#
Expand Down
2 changes: 1 addition & 1 deletion app/models/block.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def self.find_block!(query_key)
end

def self.cached_find(query_key)
Rails.cache.fetch([name, query_key], race_condition_ttl: 3.seconds) do
Rails.cache.realize([name, query_key], race_condition_ttl: 3.seconds) do
if QueryKeyUtils.valid_hex?(query_key)
block = where(block_hash: query_key).first
else
Expand Down
8 changes: 4 additions & 4 deletions app/models/cell_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ class CellInput < ApplicationRecord
after_commit :flush_cache

def find_lock_script!
Rails.cache.fetch(["CellInput", id, "lock_script"], race_condition_ttl: 3.seconds) do
Rails.cache.realize(["CellInput", id, "lock_script"], race_condition_ttl: 3.seconds) do
previous_cell_output!.lock_script
end
end

def find_type_script!
Rails.cache.fetch(["CellInput", id, "type_script"], race_condition_ttl: 3.seconds) do
Rails.cache.realize(["CellInput", id, "type_script"], race_condition_ttl: 3.seconds) do
previous_cell_output!.type_script
end
end
Expand All @@ -30,7 +30,7 @@ def previous_cell_output
end

def self.cached_find(id)
Rails.cache.fetch([name, id], race_condition_ttl: 3.seconds) { find(id) }
Rails.cache.realize([name, id], race_condition_ttl: 3.seconds) { find(id) }
end

def flush_cache
Expand All @@ -46,7 +46,7 @@ def previous_cell_output!
tx_hash = previous_output["tx_hash"]
cell_index = previous_output["index"].to_i

Rails.cache.fetch("previous_cell_output/#{tx_hash}/#{cell_index}", race_condition_ttl: 3.seconds) do
Rails.cache.realize("previous_cell_output/#{tx_hash}/#{cell_index}", race_condition_ttl: 3.seconds) do
CellOutput.find_by!(tx_hash: tx_hash, cell_index: cell_index)
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/cell_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class CellOutput < ApplicationRecord
SYSTEM_TX_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000".freeze

enum status: { live: 0, dead: 1 }
enum cell_type: { normal: 0, dao: 1 }
enum cell_type: { normal: 0, nervos_dao_deposit: 1, nervos_dao_withdrawing: 2 }

belongs_to :ckb_transaction
belongs_to :generated_by, class_name: "CkbTransaction"
Expand Down
46 changes: 24 additions & 22 deletions app/models/ckb_sync/node_data_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def update_dao_contract_related_info(local_block)
process_deposit_to_dao(dao_contract, dao_events)
process_new_dao_depositor(dao_contract, dao_events)
process_withdraw_from_dao(dao_contract, dao_events)
process_issue_subsidy(dao_contract, dao_events)
process_issue_interest(dao_contract, dao_events)
process_take_away_all_deposit(dao_contract, dao_events)
end

Expand All @@ -71,12 +71,12 @@ def process_take_away_all_deposit(dao_contract, dao_events)
end
end

def process_issue_subsidy(dao_contract, dao_events)
issue_subsidy_dao_events = dao_events.where(event_type: "issue_subsidy")
issue_subsidy_dao_events.each do |event|
dao_contract.increment!(:subsidy_granted, event.value)
def process_issue_interest(dao_contract, dao_events)
issue_interest_dao_events = dao_events.where(event_type: "issue_interest")
issue_interest_dao_events.each do |event|
dao_contract.increment!(:interest_granted, event.value)
address = event.address
address.increment!(:subsidy, event.value)
address.increment!(:interest, event.value)
event.processed!
end
end
Expand Down Expand Up @@ -170,7 +170,7 @@ def revert_dao_contract_related_operations(dao_contract, dao_events)
revert_deposit_to_dao(dao_contract, dao_events)
revert_new_dao_depositor(dao_contract, dao_events)
revert_withdraw_from_dao(dao_contract, dao_events)
revert_issue_subsidy(dao_contract, dao_events)
revert_issue_interest(dao_contract, dao_events)
revert_take_away_all_deposit(dao_contract, dao_events)
end

Expand All @@ -182,12 +182,12 @@ def revert_take_away_all_deposit(dao_contract, dao_events)
end
end

def revert_issue_subsidy(dao_contract, dao_events)
issue_subsidy_dao_events = dao_events.where(event_type: "issue_subsidy")
issue_subsidy_dao_events.each do |event|
dao_contract.decrement!(:subsidy_granted, event.value)
def revert_issue_interest(dao_contract, dao_events)
issue_interest_dao_events = dao_events.where(event_type: "issue_interest")
issue_interest_dao_events.each do |event|
dao_contract.decrement!(:interest_granted, event.value)
address = event.address
address.decrement!(:subsidy, event.value)
address.decrement!(:interest, event.value)
event.reverted!
end
end
Expand Down Expand Up @@ -374,7 +374,7 @@ def build_cell_outputs(node_outputs, ckb_transaction, addresses, outputs_data, o
end

def build_deposit_dao_events(address, cell_output, ckb_transaction, new_dao_depositor_events)
if cell_output.dao?
if cell_output.nervos_dao_deposit?
dao_contract = DaoContract.find_or_create_by(id: 1)
ckb_transaction.dao_events.build(block: ckb_transaction.block, address_id: address.id, event_type: "deposit_to_dao", value: cell_output.capacity, contract_id: dao_contract.id)
if address.dao_deposit.zero? && !new_dao_depositor_events.key?(address.id)
Expand All @@ -384,25 +384,27 @@ def build_deposit_dao_events(address, cell_output, ckb_transaction, new_dao_depo
end

def build_withdraw_dao_events(address_id, ckb_transaction_id, local_block, previous_cell_output)
if previous_cell_output.dao?
if previous_cell_output.nervos_dao_withdrawing?
withdraw_amount = previous_cell_output.capacity
ckb_transaction = CkbTransaction.find(ckb_transaction_id)
ckb_transaction.dao_events.create!(block: local_block, address_id: address_id, event_type: "withdraw_from_dao", value: withdraw_amount, contract_id: DaoContract.default_contract.id)
header_deps = ckb_transaction.header_deps
witnesses = ckb_transaction.witnesses
subsidy = CkbUtils.dao_subsidy(previous_cell_output, header_deps, witnesses)
ckb_transaction.dao_events.create!(block: local_block, address_id: address_id, event_type: "issue_subsidy", value: subsidy, contract_id: DaoContract.default_contract.id)
interest = CkbUtils.dao_interest(previous_cell_output)
ckb_transaction.dao_events.create!(block: local_block, address_id: address_id, event_type: "issue_interest", value: interest, contract_id: DaoContract.default_contract.id)
address = Address.find(address_id)
if (address.dao_deposit - withdraw_amount).zero?
ckb_transaction.dao_events.create!(block: local_block, address_id: address_id, event_type: "take_away_all_deposit", value: 1, contract_id: DaoContract.default_contract.id)
end
end
end

def cell_type(type_script)
return "normal" if type_script.blank?
def cell_type(type_script, output_data)
return "normal" unless [ENV["DAO_CODE_HASH"], ENV["DAO_TYPE_HASH"]].include?(type_script&.code_hash)

[ENV["DAO_CODE_HASH"], ENV["DAO_TYPE_HASH"]].include?(type_script.code_hash) ? "dao" : "normal"
if output_data == CKB::Utils.bin_to_hex("\x00" * 8)
"nervos_dao_deposit"
else
"nervos_dao_withdrawing"
end
end

def build_cell_output(ckb_transaction, output, address, cell_index, output_data)
Expand All @@ -414,7 +416,7 @@ def build_cell_output(ckb_transaction, output, address, cell_index, output_data)
tx_hash: ckb_transaction.tx_hash,
cell_index: cell_index,
generated_by: ckb_transaction,
cell_type: cell_type(output.type)
cell_type: cell_type(output.type, output_data)
)
end

Expand Down
23 changes: 11 additions & 12 deletions app/models/ckb_transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class CkbTransaction < ApplicationRecord
after_commit :flush_cache

def self.cached_find(query_key)
Rails.cache.fetch([name, query_key], race_condition_ttl: 3.seconds) do
Rails.cache.realize([name, query_key], race_condition_ttl: 3.seconds) do
find_by(tx_hash: query_key)
end
end
Expand Down Expand Up @@ -51,18 +51,18 @@ def income(address)
end

def dao_transaction?
inputs.dao.present? || outputs.dao.present?
inputs.where(cell_type: %w(nervos_dao_deposit nervos_dao_withdrawing))
end

private

def normal_tx_display_outputs(previews)
Rails.cache.fetch("normal_tx_display_outputs_previews_#{previews}_#{id}", race_condition_ttl: 3.seconds) do
Rails.cache.realize("normal_tx_display_outputs_previews_#{previews}_#{id}", race_condition_ttl: 3.seconds) do
cell_outputs_for_display = previews ? outputs.limit(10) : outputs
cell_outputs_for_display.order(:id).map do |output|
consumed_tx_hash = output.live? ? nil : output.consumed_by.tx_hash
display_output = { id: output.id, capacity: output.capacity, address_hash: output.address_hash, status: output.status, consumed_tx_hash: consumed_tx_hash, cell_type: output.cell_type }
display_output.merge!({ dao_type_hash: ENV["DAO_TYPE_HASH"] }) if output.dao?
display_output.merge!({ dao_type_hash: ENV["DAO_TYPE_HASH"] }) unless output.normal?

display_output
end
Expand All @@ -79,27 +79,26 @@ def cellbase_display_outputs
end

def normal_tx_display_inputs(previews)
Rails.cache.fetch("normal_tx_display_inputs_previews_#{previews}_#{id}", race_condition_ttl: 3.seconds) do
Rails.cache.realize("normal_tx_display_inputs_previews_#{previews}_#{id}", race_condition_ttl: 3.seconds) do
cell_inputs_for_display = previews ? cell_inputs.limit(10) : cell_inputs
cell_inputs_for_display.order(:id).map do |cell_input|
previous_cell_output = cell_input.previous_cell_output
display_input = { id: previous_cell_output.id, from_cellbase: false, capacity: previous_cell_output.capacity, address_hash: previous_cell_output.address_hash, generated_tx_hash: previous_cell_output.generated_by.tx_hash, cell_type: previous_cell_output.cell_type }
display_input.merge!(attributes_for_dao_input(previous_cell_output)) if previous_cell_output.dao?
display_input.merge!(attributes_for_dao_input(previous_cell_output)) if previous_cell_output.nervos_dao_withdrawing?

display_input
end
end
end

def attributes_for_dao_input(input)
witness = witnesses[input.cell_index]
header_deps_index = CKB::Utils.bin_to_hex(CKB::Utils.hex_to_bin(witness)[-8..-1]).hex
withdraw_block_hash = header_deps[header_deps_index]
started_block_number = Block.find(input.block_id).number
withdraw_block_hash = input.block.block_hash
nervos_dao_withdrawing_cell_generated_tx = input.generated_by
started_block_number = Block.find(nervos_dao_withdrawing_cell_generated_tx.block.id).number
ended_block_number = Block.find_by(block_hash: withdraw_block_hash).number
subsidy = CkbUtils.dao_subsidy(input, header_deps, witnesses)
interest = CkbUtils.dao_interest(input)

{ started_block_number: started_block_number, ended_block_number: ended_block_number, subsidy: subsidy, dao_type_hash: ENV["DAO_TYPE_HASH"] }
{ started_block_number: started_block_number, ended_block_number: ended_block_number, interest: interest, dao_type_hash: ENV["DAO_TYPE_HASH"] }
end

def cellbase_display_inputs
Expand Down
7 changes: 4 additions & 3 deletions app/models/dao_contract.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
class DaoContract < ApplicationRecord
validates :total_deposit, :subsidy_granted, :deposit_transactions_count, :withdraw_transactions_count, :depositors_count, :total_depositors_count, presence: true, numericality: { greater_than_or_equal_to: 0 }
validates :total_deposit, :interest_granted, :deposit_transactions_count, :withdraw_transactions_count, :depositors_count, :total_depositors_count, presence: true, numericality: { greater_than_or_equal_to: 0 }
CONTRACT_NAME = "nervos_dao"

def self.default_contract
find_or_create_by(id: 1)
end

def ckb_transactions
ckb_transaction_ids = CellOutput.dao.select("ckb_transaction_id")
ckb_transaction_ids = CellOutput.where(cell_type: %w(nervos_dao_deposit nervos_dao_withdrawing)).select("ckb_transaction_id")
CkbTransaction.where(id: ckb_transaction_ids)
end
end
Expand All @@ -17,7 +18,7 @@ def ckb_transactions
#
# id :bigint not null, primary key
# total_deposit :decimal(30, ) default(0)
# subsidy_granted :decimal(30, ) default(0)
# interest_granted :decimal(30, ) default(0)
# deposit_transactions_count :bigint default(0)
# withdraw_transactions_count :bigint default(0)
# depositors_count :integer default(0)
Expand Down
2 changes: 1 addition & 1 deletion app/models/dao_event.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class DaoEvent < ApplicationRecord
enum event_type: { deposit_to_dao: 0, new_dao_depositor: 1, withdraw_from_dao: 2, issue_subsidy: 3, take_away_all_deposit: 4 }
enum event_type: { deposit_to_dao: 0, new_dao_depositor: 1, withdraw_from_dao: 2, issue_interest: 3, take_away_all_deposit: 4 }
enum status: { pending: 0, processed: 1, reverted: 2 }
validates :value, presence: true, numericality: { greater_than_or_equal_to: 0 }

Expand Down
2 changes: 1 addition & 1 deletion app/models/miner_ranking.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def id

def ranking(limit = nil)
limit = limit.presence || DEFAULT_LIMIT
Rails.cache.fetch("miner_ranking", expires_in: 1.hour, race_condition_ttl: 10.seconds) do
Rails.cache.realize("miner_ranking", expires_in: 1.hour, race_condition_ttl: 10.seconds) do
ranking_infos.take(limit)
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/net_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def version
end

def local_node_info
Rails.cache.fetch("local_node_info") do
Rails.cache.realize("local_node_info") do
CkbSync::Api.instance.local_node_info
end
end
Expand Down
8 changes: 4 additions & 4 deletions app/models/statistic_info_chart.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def id

def hash_rate
to = Rails.cache.read("hash_rate_to")
Rails.cache.fetch("hash_rate_chart_data_#{to}")&.uniq || []
Rails.cache.realize("hash_rate_chart_data_#{to}")&.uniq || []
end

def uncle_rate
Expand All @@ -23,7 +23,7 @@ def uncle_rate
def difficulty
current_epoch_number = CkbSync::Api.instance.get_current_epoch.number

Rails.cache.fetch("statistic_info_difficulty_#{current_epoch_number}", expires_in: 10.minutes, race_condition_ttl: 10.seconds) do
Rails.cache.realize("statistic_info_difficulty_#{current_epoch_number}", expires_in: 10.minutes, race_condition_ttl: 10.seconds) do
from = Block.where(epoch: 0).recent.first&.number.to_i
to = Block.maximum(:number).to_i
hash_rate_block_numbers = (from + 1).step(to, 100).to_a
Expand All @@ -37,8 +37,8 @@ def difficulty

def calculate_hash_rate
max_block_number = Block.maximum(:number).to_i
from = Rails.cache.fetch("hash_rate_from") { last_epoch0_block_number }
to = Rails.cache.fetch("hash_rate_to") { max_block_number }
from = Rails.cache.realize("hash_rate_from") { last_epoch0_block_number }
to = Rails.cache.realize("hash_rate_to") { max_block_number }

epoch_first_block_numbers = Block.order(:epoch, :timestamp).select("distinct on (epoch) number").to_a.pluck(:number)
result =
Expand Down
10 changes: 9 additions & 1 deletion app/presenters/address_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ def balance
object.reduce(0) { |sum, addr| sum + addr.balance.to_i }
end

def dao_deposit
object.reduce(0) { |sum, addr| sum + addr.dao_deposit.to_i }
end

def interest
object.reduce(0) { |sum, addr| sum + addr.interest.to_i }
end

def lock_script
object.first.cached_lock_script
end
Expand All @@ -34,7 +42,7 @@ def ckb_transactions

def ckb_dao_transactions
address_ids = object.pluck(:id)
ckb_transaction_ids = CellOutput.where(address_id: address_ids).dao.select("ckb_transaction_id")
ckb_transaction_ids = CellOutput.where(address_id: address_ids).where(cell_type: %w(nervos_dao_deposit nervos_dao_withdrawing)).select("ckb_transaction_id")
CkbTransaction.where(id: ckb_transaction_ids)
end

Expand Down
6 changes: 6 additions & 0 deletions app/serializers/address_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,10 @@ class AddressSerializer
attribute :pending_reward_blocks_count do |object|
object.pending_reward_blocks_count.to_s
end
attribute :dao_deposit do |object|
object.dao_deposit.to_s
end
attribute :interest do |object|
object.interest.to_s
end
end
Loading

0 comments on commit 82a5cbf

Please sign in to comment.