diff --git a/CHANGELOG.md b/CHANGELOG.md index 351143be9..5e1326654 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,54 @@ +# [v0.9.6](https://github.com/shaojunda/ckb-explorer/compare/v0.9.5...v0.9.6) (2020-06-01) + + +### Bug Fixes + +* task bug ([48c735c](https://github.com/shaojunda/ckb-explorer/commit/48c735c)) + + +### Features + +* add average_block_time to daily statistic ([ed2519d](https://github.com/shaojunda/ckb-explorer/commit/ed2519d)) +* add block time statistic ([26898c4](https://github.com/shaojunda/ckb-explorer/commit/26898c4)) +* add block_propagation_delay table ([09c7643](https://github.com/shaojunda/ckb-explorer/commit/09c7643)) +* add block_propagation_delay_history ([8cf7293](https://github.com/shaojunda/ckb-explorer/commit/8cf7293)) +* add block_size column to blocks ([fec68e0](https://github.com/shaojunda/ckb-explorer/commit/fec68e0)) +* add circulating supply to daily statistics ([a63e01f](https://github.com/shaojunda/ckb-explorer/commit/a63e01f)) +* add circulation ratio to daily statistic ([64717a5](https://github.com/shaojunda/ckb-explorer/commit/64717a5)) +* add epoch distribution info generation task ([42f53a3](https://github.com/shaojunda/ckb-explorer/commit/42f53a3)) +* add epoch length to epoch statistics ([1ad1249](https://github.com/shaojunda/ckb-explorer/commit/1ad1249)) +* add epoch_length_distribution ([68c9d61](https://github.com/shaojunda/ckb-explorer/commit/68c9d61)) +* add epoch_time_distribution ([2c40104](https://github.com/shaojunda/ckb-explorer/commit/2c40104)) +* add epoch_time_distribution ([7aac8db](https://github.com/shaojunda/ckb-explorer/commit/7aac8db)) +* add fill block size task ([5146ecf](https://github.com/shaojunda/ckb-explorer/commit/5146ecf)) +* add inflation_rate ([bc5cdd8](https://github.com/shaojunda/ckb-explorer/commit/bc5cdd8)) +* add liquidity to daily statistic ([493a50c](https://github.com/shaojunda/ckb-explorer/commit/493a50c)) +* add locked_capacity to daily statistics ([c1e0bf9](https://github.com/shaojunda/ckb-explorer/commit/c1e0bf9)) +* add miner_addresses_distribution ([f8752dd](https://github.com/shaojunda/ckb-explorer/commit/f8752dd)) +* add monetary data serializer ([8c7d14c](https://github.com/shaojunda/ckb-explorer/commit/8c7d14c)) +* add monetary data show action ([4feedeb](https://github.com/shaojunda/ckb-explorer/commit/4feedeb)) +* add monetary data validator ([ed14322](https://github.com/shaojunda/ckb-explorer/commit/ed14322)) +* add more columns to daily statistics ([ffe1fc1](https://github.com/shaojunda/ckb-explorer/commit/ffe1fc1)) +* add new column to daily statistics ([871aefe](https://github.com/shaojunda/ckb-explorer/commit/871aefe)) +* add new columns ([9b69d89](https://github.com/shaojunda/ckb-explorer/commit/9b69d89)) +* add nominal apc ([6b24e77](https://github.com/shaojunda/ckb-explorer/commit/6b24e77)) +* add real_inflation_rate ([098c930](https://github.com/shaojunda/ckb-explorer/commit/098c930)) +* add total supply to daily statistic ([8c383bd](https://github.com/shaojunda/ckb-explorer/commit/8c383bd)) +* add total tx fee column to daily statistic ([05669e2](https://github.com/shaojunda/ckb-explorer/commit/05669e2)) +* add transaction propagation delays ([bf9651c](https://github.com/shaojunda/ckb-explorer/commit/bf9651c)) +* add udt account model ([2b5c1f0](https://github.com/shaojunda/ckb-explorer/commit/2b5c1f0)) +* add udt model ([74fbcf7](https://github.com/shaojunda/ckb-explorer/commit/74fbcf7)) +* generate epoch_time_distribution ([3a175b9](https://github.com/shaojunda/ckb-explorer/commit/3a175b9)) +* return epoch_length_distribution ([b7de134](https://github.com/shaojunda/ckb-explorer/commit/b7de134)) +* show circulating_supply ([260f158](https://github.com/shaojunda/ckb-explorer/commit/260f158)) + + +### Performance Improvements + +* speed up epoch statistic generator ([f3a059a](https://github.com/shaojunda/ckb-explorer/commit/f3a059a)) + + + # [v0.9.5](https://github.com/shaojunda/ckb-explorer/compare/v0.9.4...v0.9.5) (2020-02-26) - prevent divided by 0 on average deposit time ([cabfa48](https://github.com/nervosnetwork/ckb-explorer/commit/cabfa48)) diff --git a/Gemfile b/Gemfile index c5f6b3d8c..d1f9453b9 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ gem "rails", "~> 6.0.0" # Use postgresql as the database for Active Record gem "pg", ">= 0.18", "< 2.0" # Use Puma as the app server -gem "puma", "~> 4.3.3" +gem "puma", "~> 4.3.5" # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder # gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production diff --git a/Gemfile.lock b/Gemfile.lock index 1ce194521..ba85def5c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -24,63 +24,63 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (6.0.0) - actionpack (= 6.0.0) + actioncable (6.0.3.1) + actionpack (= 6.0.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.0) - actionpack (= 6.0.0) - activejob (= 6.0.0) - activerecord (= 6.0.0) - activestorage (= 6.0.0) - activesupport (= 6.0.0) + actionmailbox (6.0.3.1) + actionpack (= 6.0.3.1) + activejob (= 6.0.3.1) + activerecord (= 6.0.3.1) + activestorage (= 6.0.3.1) + activesupport (= 6.0.3.1) mail (>= 2.7.1) - actionmailer (6.0.0) - actionpack (= 6.0.0) - actionview (= 6.0.0) - activejob (= 6.0.0) + actionmailer (6.0.3.1) + actionpack (= 6.0.3.1) + actionview (= 6.0.3.1) + activejob (= 6.0.3.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.0) - actionview (= 6.0.0) - activesupport (= 6.0.0) - rack (~> 2.0) + actionpack (6.0.3.1) + actionview (= 6.0.3.1) + activesupport (= 6.0.3.1) + rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.0) - actionpack (= 6.0.0) - activerecord (= 6.0.0) - activestorage (= 6.0.0) - activesupport (= 6.0.0) + actiontext (6.0.3.1) + actionpack (= 6.0.3.1) + activerecord (= 6.0.3.1) + activestorage (= 6.0.3.1) + activesupport (= 6.0.3.1) nokogiri (>= 1.8.5) - actionview (6.0.0) - activesupport (= 6.0.0) + actionview (6.0.3.1) + activesupport (= 6.0.3.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.0) - activesupport (= 6.0.0) + activejob (6.0.3.1) + activesupport (= 6.0.3.1) globalid (>= 0.3.6) - activemodel (6.0.0) - activesupport (= 6.0.0) - activerecord (6.0.0) - activemodel (= 6.0.0) - activesupport (= 6.0.0) + activemodel (6.0.3.1) + activesupport (= 6.0.3.1) + activerecord (6.0.3.1) + activemodel (= 6.0.3.1) + activesupport (= 6.0.3.1) activerecord-import (1.0.3) activerecord (>= 3.2) - activestorage (6.0.0) - actionpack (= 6.0.0) - activejob (= 6.0.0) - activerecord (= 6.0.0) + activestorage (6.0.3.1) + actionpack (= 6.0.3.1) + activejob (= 6.0.3.1) + activerecord (= 6.0.3.1) marcel (~> 0.3.1) - activesupport (6.0.0) + activesupport (6.0.3.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - zeitwerk (~> 2.1, >= 2.1.8) + zeitwerk (~> 2.2, >= 2.2.2) addressable (2.6.0) public_suffix (>= 2.0.2, < 4.0) annotate (2.7.5) @@ -93,7 +93,7 @@ GEM ffi (>= 1.9.25) bootsnap (1.4.4) msgpack (~> 1.0) - builder (3.2.3) + builder (3.2.4) chronic_duration (0.10.6) numerizer (~> 0.1.1) codecov (0.1.14) @@ -101,7 +101,7 @@ GEM simplecov url coderay (1.1.2) - concurrent-ruby (1.1.5) + concurrent-ruby (1.1.6) config (1.7.2) activesupport (>= 3.0) deep_merge (~> 1.2, >= 1.2.1) @@ -109,7 +109,7 @@ GEM connection_pool (2.2.2) crack (0.4.3) safe_yaml (~> 1.0.0) - crass (1.0.5) + crass (1.0.6) daemons (1.3.1) database_cleaner (1.7.0) deep_merge (1.2.1) @@ -147,7 +147,7 @@ GEM dry-logic (~> 0.5, >= 0.5.0) dry-types (~> 0.14.0) equatable (0.5.0) - erubi (1.8.0) + erubi (1.9.0) et-orbi (1.2.2) tzinfo factory_bot (5.0.2) @@ -165,27 +165,27 @@ GEM activesupport (>= 4.2.0) hashdiff (1.0.0) hiredis (0.6.3) - i18n (1.7.0) + i18n (1.8.2) concurrent-ruby (~> 1.0) jaro_winkler (1.5.2) json (2.2.0) - kaminari (1.1.1) + kaminari (1.2.1) activesupport (>= 4.1.0) - kaminari-actionview (= 1.1.1) - kaminari-activerecord (= 1.1.1) - kaminari-core (= 1.1.1) - kaminari-actionview (1.1.1) + kaminari-actionview (= 1.2.1) + kaminari-activerecord (= 1.2.1) + kaminari-core (= 1.2.1) + kaminari-actionview (1.2.1) actionview - kaminari-core (= 1.1.1) - kaminari-activerecord (1.1.1) + kaminari-core (= 1.2.1) + kaminari-activerecord (1.2.1) activerecord - kaminari-core (= 1.1.1) - kaminari-core (1.1.1) + kaminari-core (= 1.2.1) + kaminari-core (1.2.1) listen (3.1.5) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) ruby_dep (~> 1.2) - loofah (2.3.1) + loofah (2.5.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -194,7 +194,7 @@ GEM mimemagic (~> 0.3.2) metaclass (0.0.4) method_source (0.9.2) - mimemagic (0.3.3) + mimemagic (0.3.5) mina (1.2.3) open4 (~> 1.3.4) rake @@ -202,7 +202,7 @@ GEM mina (~> 1.0) mini_mime (1.0.2) mini_portile2 (2.4.0) - minitest (5.12.2) + minitest (5.14.1) minitest-reporters (1.3.6) ansi builder @@ -215,7 +215,7 @@ GEM connection_pool (~> 2.2) newrelic_rpm (6.4.0.356) nio4r (2.5.2) - nokogiri (1.10.8) + nokogiri (1.10.9) mini_portile2 (~> 2.4.0) numerizer (0.1.1) open4 (1.3.4) @@ -232,10 +232,10 @@ GEM pry-nav (0.3.0) pry (>= 0.9.10, < 0.13.0) public_suffix (3.1.0) - puma (4.3.3) + puma (4.3.5) nio4r (~> 2.0) raabro (1.1.6) - rack (2.0.8) + rack (2.2.2) rack-attack (6.2.1) rack (>= 1.0, < 3) rack-cors (1.0.5) @@ -244,29 +244,29 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.0) - actioncable (= 6.0.0) - actionmailbox (= 6.0.0) - actionmailer (= 6.0.0) - actionpack (= 6.0.0) - actiontext (= 6.0.0) - actionview (= 6.0.0) - activejob (= 6.0.0) - activemodel (= 6.0.0) - activerecord (= 6.0.0) - activestorage (= 6.0.0) - activesupport (= 6.0.0) + rails (6.0.3.1) + actioncable (= 6.0.3.1) + actionmailbox (= 6.0.3.1) + actionmailer (= 6.0.3.1) + actionpack (= 6.0.3.1) + actiontext (= 6.0.3.1) + actionview (= 6.0.3.1) + activejob (= 6.0.3.1) + activemodel (= 6.0.3.1) + activerecord (= 6.0.3.1) + activestorage (= 6.0.3.1) + activesupport (= 6.0.3.1) bundler (>= 1.3.0) - railties (= 6.0.0) + railties (= 6.0.3.1) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.2.0) - loofah (~> 2.2, >= 2.2.2) - railties (6.0.0) - actionpack (= 6.0.0) - activesupport (= 6.0.0) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (6.0.3.1) + actionpack (= 6.0.3.1) + activesupport (= 6.0.3.1) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -326,7 +326,7 @@ GEM spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) spring (>= 1.2, < 3.0) - sprockets (3.7.2) + sprockets (4.0.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.2.1) @@ -349,7 +349,7 @@ GEM tty-screen (0.6.5) tty-tree (0.3.0) tty-which (0.4.1) - tzinfo (1.2.5) + tzinfo (1.2.7) thread_safe (~> 0.1) unicode-display_width (1.6.0) unicode_utils (1.4.0) @@ -359,10 +359,10 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - websocket-driver (0.7.1) + websocket-driver (0.7.2) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.4) - zeitwerk (2.2.0) + zeitwerk (2.3.0) PLATFORMS ruby @@ -392,7 +392,7 @@ DEPENDENCIES pg (>= 0.18, < 2.0) pry pry-nav - puma (~> 4.3.3) + puma (~> 4.3.5) rack-attack rack-cors rails (~> 6.0.0) diff --git a/app/controllers/api/v1/distribution_data_controller.rb b/app/controllers/api/v1/distribution_data_controller.rb index 086251739..4679df893 100644 --- a/app/controllers/api/v1/distribution_data_controller.rb +++ b/app/controllers/api/v1/distribution_data_controller.rb @@ -2,9 +2,10 @@ module Api module V1 class DistributionDataController < ApplicationController before_action :validate_query_params, only: :show + def show distribution_data = DistributionData.new - render json: DistributionDataSerializer.new(distribution_data, { params: { indicator: params[:id] } }) + render json: DistributionDataSerializer.new(distribution_data, params: { indicator: params[:id] }) end private diff --git a/app/controllers/api/v1/market_data_controller.rb b/app/controllers/api/v1/market_data_controller.rb index 12938dfda..4e7f491df 100644 --- a/app/controllers/api/v1/market_data_controller.rb +++ b/app/controllers/api/v1/market_data_controller.rb @@ -4,7 +4,7 @@ class MarketDataController < ApplicationController skip_before_action :check_header_info def show - render json: MarketData.new(params[:id]).call + render json: MarketData.new(indicator: params[:id]).call end end end diff --git a/app/controllers/api/v1/monetary_data_controller.rb b/app/controllers/api/v1/monetary_data_controller.rb new file mode 100644 index 000000000..0a75148ef --- /dev/null +++ b/app/controllers/api/v1/monetary_data_controller.rb @@ -0,0 +1,24 @@ +module Api + module V1 + class MonetaryDataController < ApplicationController + before_action :validate_query_params, only: :show + + def show + monetary_data = MonetaryData.new + + render json: MonetaryDataSerializer.new(monetary_data, params: { indicator: params[:id] }) + end + + def validate_query_params + validator = Validations::MonetaryData.new(params) + + if validator.invalid? + errors = validator.error_object[:errors] + status = validator.error_object[:status] + + render json: errors, status: status + end + end + end + end +end diff --git a/app/controllers/validations/monetary_data.rb b/app/controllers/validations/monetary_data.rb new file mode 100644 index 000000000..bb1444249 --- /dev/null +++ b/app/controllers/validations/monetary_data.rb @@ -0,0 +1,39 @@ +module Validations + class MonetaryData + include ActiveModel::Validations + + validate :query_key_format_must_be_correct + + def initialize(params = {}) + @query_key = params[:id] + end + + def error_object + api_errors = [] + + if invalid? + api_errors << Api::V1::Exceptions::IndicatorNameInvalidError.new if :query_key.in?(errors.keys) + { + status: api_errors.first.status, + errors: RequestErrorSerializer.new(api_errors, message: api_errors.first.title) + } + end + end + + private + + attr_accessor :query_key + + def query_key_format_must_be_correct + if query_key.blank? || !query_key_valid? + errors.add(:query_key, "indicator name is invalid") + end + end + + def query_key_valid? + query_keys = query_key.split("-") + extra_keys = query_keys - ::MonetaryData::VALID_INDICATORS + extra_keys.blank? || extra_keys.size == 1 && extra_keys.first =~ /^nominal_apc(\d+)$/ + end + end +end diff --git a/app/lib/fast_jsonapi/pagination_meta_generator.rb b/app/lib/fast_jsonapi/pagination_meta_generator.rb index 5143e99a9..037c938c6 100644 --- a/app/lib/fast_jsonapi/pagination_meta_generator.rb +++ b/app/lib/fast_jsonapi/pagination_meta_generator.rb @@ -53,7 +53,7 @@ def include_page?(page) end def query_string(query_params) - query_params.reject{ |key| key.in?(%w(page page_size)) }.map{|k,v| "?#{k}=#{v}" }.join("?") + query_params.reject { |key| key.in?(%w(page page_size)) }.map { |k, v| "?#{k}=#{v}" }.join("?") end def limit_page_size(records, page_size) diff --git a/app/models/block_time_statistic.rb b/app/models/block_time_statistic.rb index fbe50f4cc..cb1498000 100644 --- a/app/models/block_time_statistic.rb +++ b/app/models/block_time_statistic.rb @@ -26,10 +26,9 @@ def generate(started_at, ended_at) values << item end - current_time = current_time + 1.days + current_time = current_time + 1.day end - BlockTimeStatistic.upsert_all(values, unique_by: :stat_timestamp) end diff --git a/app/models/daily_statistic.rb b/app/models/daily_statistic.rb index ad59c46eb..26cd50c9a 100644 --- a/app/models/daily_statistic.rb +++ b/app/models/daily_statistic.rb @@ -2,8 +2,17 @@ class DailyStatistic < ApplicationRecord VALID_INDICATORS = %w( transactions_count addresses_count total_dao_deposit live_cells_count dead_cells_count avg_hash_rate avg_difficulty uncle_rate total_depositors_count address_balance_distribution total_tx_fee occupied_capacity daily_dao_deposit daily_dao_depositors_count - circulation_ratio daily_dao_withdraw nodes_count + circulation_ratio daily_dao_withdraw nodes_count circulating_supply burnt locked_capacity treasury_amount mining_reward + deposit_compensation liquidity ).freeze + + def burnt + treasury_amount.to_i + MarketData::BURN_QUOTA + end + + def liquidity + circulating_supply - total_dao_deposit.to_d + end end # == Schema Information @@ -47,4 +56,5 @@ class DailyStatistic < ApplicationRecord # average_block_time :jsonb # nodes_distribution :jsonb # nodes_count :integer +# locked_capacity :decimal(30, ) # diff --git a/app/models/dao_contract.rb b/app/models/dao_contract.rb index 6a4151da7..6e35e95dc 100644 --- a/app/models/dao_contract.rb +++ b/app/models/dao_contract.rb @@ -43,7 +43,7 @@ def estimated_apc(deposit_epoch = tip_block_fraction_epoch, deposited_epochs = E rate(start_epoch, end_epoch) end rate = rates.reduce(1) { |memo, rate| memo * (1 + rate) } - 1 - (rate * 100) / ratio + ((rate * 100) / ratio).truncate(4) end def deposit_changes diff --git a/app/models/distribution_data.rb b/app/models/distribution_data.rb index bfb51a3c7..f1e632250 100644 --- a/app/models/distribution_data.rb +++ b/app/models/distribution_data.rb @@ -1,5 +1,9 @@ class DistributionData - VALID_INDICATORS = %w(address_balance_distribution block_time_distribution epoch_time_distribution epoch_length_distribution average_block_time nodes_distribution block_propagation_delay_history transaction_propagation_delay_history).freeze + VALID_INDICATORS = %w( + address_balance_distribution block_time_distribution epoch_time_distribution epoch_length_distribution + average_block_time nodes_distribution block_propagation_delay_history transaction_propagation_delay_history + miner_address_distribution + ).freeze def id Time.current.to_i @@ -72,4 +76,15 @@ def transaction_propagation_delay_history TransactionPropagationDelay.connection.select_all(sql) end + + def miner_address_distribution + Rails.cache.realize("miner_address_distribution", expires_in: 1.day) do + result = Block.where("timestamp >= ?", CkbUtils.time_in_milliseconds(7.days.ago.to_i)).group(:miner_hash).order("count(miner_hash) desc").count.to_a + if result.present? + (result[0..9].map{ |item| [item[0], item[1].to_s] } + [["other", result[10..-1].map { |item| item[1] }.reduce(:+).to_s]]).to_h + else + result + end + end + end end diff --git a/app/models/market_data.rb b/app/models/market_data.rb index a00d764ea..19a81d170 100644 --- a/app/models/market_data.rb +++ b/app/models/market_data.rb @@ -8,12 +8,13 @@ class MarketData FOUNDING_PARTNER_QUOTA = INITIAL_SUPPLY * 0.05 FOUNDATION_RESERVE_QUOTA = INITIAL_SUPPLY * 0.02 - attr_reader :indicator, :current_timestamp, :tip_block_number + attr_reader :indicator, :current_timestamp, :tip_block_number, :unit - def initialize(indicator = nil, tip_block_number = nil) + def initialize(indicator: nil, tip_block_number: nil, unit: "ckb") @indicator = indicator - @current_timestamp = CkbUtils.time_in_milliseconds(Time.find_zone("UTC").now) @tip_block_number = tip_block_number + @unit = unit + @current_timestamp = tip_block_number.blank? ? CkbUtils.time_in_milliseconds(Time.find_zone("UTC").now) : tip_block.timestamp end def call @@ -22,32 +23,6 @@ def call send(indicator) end - private - - def parsed_dao - @parsed_dao ||= - begin - tip_block = tip_block_number.present? ? Block.find_by(number: tip_block_number) : Block.recent.first - CkbUtils.parse_dao(tip_block.dao) - end - end - - def total_supply - if current_timestamp > first_released_timestamp_may - result = parsed_dao.c_i - BURN_QUOTA - yesterday_treasury_amount.to_i - else - result = parsed_dao.c_i - BURN_QUOTA - end - - (result / 10**8).truncate(8) - end - - def circulating_supply - result = parsed_dao.c_i - parsed_dao.s_i - BURN_QUOTA - ecosystem_locked - team_locked - private_sale_locked - founding_partners_locked - foundation_reserve_locked - bug_bounty_locked - - (result / 10**8).truncate(8) - end - def ecosystem_locked if current_timestamp < first_released_timestamp_other ECOSYSTEM_QUOTA * 0.97 @@ -93,37 +68,87 @@ def foundation_reserve_locked end def bug_bounty_locked - Address.find_by(address_hash: "ckb1qyqy6mtud5sgctjwgg6gydd0ea05mr339lnslczzrc").balance + Address.find_by(address_hash: "ckb1qyqy6mtud5sgctjwgg6gydd0ea05mr339lnslczzrc")&.balance.to_i + end + + private + + def tip_block + @tip_block ||= tip_block_number.present? ? Block.find_by(number: tip_block_number) : Block.recent.first + end + + def parsed_dao + @parsed_dao ||= CkbUtils.parse_dao(tip_block.dao) + end + + def total_supply + if current_timestamp > first_released_timestamp_may + result = parsed_dao.c_i - BURN_QUOTA - yesterday_treasury_amount.to_i + else + result = parsed_dao.c_i - BURN_QUOTA + end + + unit == "ckb" ? (result / 10**8).truncate(8) : result + end + + def circulating_supply + result = parsed_dao.c_i - parsed_dao.s_i - BURN_QUOTA - ecosystem_locked - team_locked - private_sale_locked - founding_partners_locked - foundation_reserve_locked - bug_bounty_locked + + unit == "ckb" ? (result / 10**8).truncate(8) : result end # 2020-05-01 def first_released_timestamp_may - @first_released_timestamp_may ||= Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn323t90gna20lusyshreg32qee4fhkt9jj2t6qrqzzqxzq8yqt8kmd9").lock_script.lock_info[:estimated_unlock_time].to_i + @first_released_timestamp_may ||= + begin + lock_address = Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn323t90gna20lusyshreg32qee4fhkt9jj2t6qrqzzqxzq8yqt8kmd9") + lock_address.present? ? lock_address.lock_script.lock_info[:estimated_unlock_time].to_i : Time.find_zone("UTC").parse("2020-05-01").to_i + end end # 2021-05-01 def second_released_timestamp_may - @second_released_timestamp_may ||= Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn323crn7nscet5sfwxjkzhexymfa4zntzt8vasvqzzqxzq8yq92pgkg").lock_script.lock_info[:estimated_unlock_time].to_i + @second_released_timestamp_may ||= + begin + lock_address = Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn323crn7nscet5sfwxjkzhexymfa4zntzt8vasvqzzqxzq8yq92pgkg") + lock_address.present? ? lock_address.lock_script.lock_info[:estimated_unlock_time].to_i : Time.find_zone("UTC").parse("2021-05-01").to_i + end end # 2022-05-01 def third_released_timestamp_may - @third_released_timestamp_may ||= Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sl0qgva2l78fcnjt6x8kr8sln4lqs4twcpq4qzzqxzq8yq7hpadu").lock_script.lock_info[:estimated_unlock_time].to_i + @third_released_timestamp_may ||= + begin + lock_address = Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sl0qgva2l78fcnjt6x8kr8sln4lqs4twcpq4qzzqxzq8yq7hpadu") + lock_address.present? ? lock_address.lock_script.lock_info[:estimated_unlock_time].to_i : Time.find_zone("UTC").parse("2022-05-01").to_i + end end # 2020-07-01 def first_released_timestamp_other - @first_released_timestamp_other ||= Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32s3y29vjv73cfm8qax220dwwmpdccl4upy4s9qzzqxzq8yqyd09am").lock_script.lock_info[:estimated_unlock_time].to_i + @first_released_timestamp_other ||= + begin + lock_address = Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32s3y29vjv73cfm8qax220dwwmpdccl4upy4s9qzzqxzq8yqyd09am") + lock_address.present? ? lock_address.lock_script.lock_info[:estimated_unlock_time].to_i : Time.find_zone("UTC").parse("2020-07-01").to_i + end end # 2020-12-31 def second_released_timestamp_other - @second_released_timestamp_other ||= Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sn23uga5m8u5v87q98vr29qa8tl0ruu84gqfqzzqxzq8yqc2dxk6").lock_script.lock_info[:estimated_unlock_time].to_i + @second_released_timestamp_other ||= + begin + lock_address = Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sn23uga5m8u5v87q98vr29qa8tl0ruu84gqfqzzqxzq8yqc2dxk6") + lock_address.present? ? lock_address.lock_script.lock_info[:estimated_unlock_time].to_i : Time.find_zone("UTC").parse("2020-12-31").to_i + end end # 2022-12-31 def third_released_timestamp_other - @third_released_timestamp_other ||= Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sdufwedw7a0w9dkvhpsah4mdk2gkfq63e0q6qzzqxzq8yqnqq85p").lock_script.lock_info[:estimated_unlock_time].to_i + @third_released_timestamp_other ||= + begin + lock_address = Address.find_by(address_hash: "ckb1q3w9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sdufwedw7a0w9dkvhpsah4mdk2gkfq63e0q6qzzqxzq8yqnqq85p") + lock_address.present? ? lock_address.lock_script.lock_info[:estimated_unlock_time].to_i : Time.find_zone("UTC").parse("2022-12-31").to_i + end end def yesterday_treasury_amount diff --git a/app/models/monetary_data.rb b/app/models/monetary_data.rb new file mode 100644 index 000000000..909913bd7 --- /dev/null +++ b/app/models/monetary_data.rb @@ -0,0 +1,76 @@ +class MonetaryData + VALID_INDICATORS = %w(nominal_apc nominal_inflation_rate real_inflation_rate).freeze + INITIAL_SUPPLY = 33.6 + SECONDARY_SUPPLY_PER_YEAR = 1.344 + + def initialize + @total_supplies_per_year = {} + end + + def id + Time.current.to_i + end + + def nominal_apc(max_year = 20) + Rails.cache.realize("nominal_apc#{max_year}") do + total_supplies_per_year(max_year).each_with_index.map do |_, index| + cumulative_total_supply = index.zero? ? 0 : (0..index).reduce(0) { |memo, value| memo + total_supplies_per_year(max_year)[value] } + total_supply_so_far = INITIAL_SUPPLY + cumulative_total_supply + (SECONDARY_SUPPLY_PER_YEAR / total_supply_so_far * 100).truncate(8) + end + end + end + + def nominal_inflation_rate(max_year = 50) + Rails.cache.realize("nominal_inflation_rate#{max_year}") do + secondary_issuance_monthly = SECONDARY_SUPPLY_PER_YEAR / 12 + rs = + total_supplies_per_year(max_year).each_with_index.map do |_, index| + cumulative_total_supply = index.zero? ? 0 : (0..index).reduce(0) { |memo, value| memo + total_supplies_per_year(max_year)[value] } + INITIAL_SUPPLY + cumulative_total_supply + end + primary_supplies_per_year.map { |item| item + secondary_issuance_monthly }.zip(rs).map { |item| (item.reduce(:/) * 12 * 100).truncate(8) } + end + end + + def real_inflation_rate(max_year = 50) + Rails.cache.realize("real_inflation#{max_year}") do + nominal_inflation_rate(max_year).zip(nominal_apc(max_year)).map { |item| item.reduce(:-).truncate(8) } + end + end + + private + + def total_supplies_per_year(max_year) + @total_supplies_per_year[max_year] ||= + begin + secondary_supply_per_month = SECONDARY_SUPPLY_PER_YEAR / 12 + total_supplies_per_year = + (0...max_year).each_with_index.map do |year, index| + primary_supply_per_year = 4.2 / (2**(year / 4)) + primary_supply_per_month = primary_supply_per_year / 12 + if index.zero? + [0] + [primary_supply_per_month + secondary_supply_per_month] * 11 + else + [primary_supply_per_month + secondary_supply_per_month] * 12 + end + end + + total_supplies_per_year.flatten + end + end + + def primary_supplies_per_year + @primary_supplies_per_year ||= + begin + max_year = 50 + primary_supplies_per_year = + (0...max_year).map do |year| + primary_supply_per_year = 4.2 / (2**(year / 4)) + [primary_supply_per_year / 12] * 12 + end + + primary_supplies_per_year.flatten + end + end +end diff --git a/app/models/statistic_info.rb b/app/models/statistic_info.rb index c2ceb824c..af6594fcf 100644 --- a/app/models/statistic_info.rb +++ b/app/models/statistic_info.rb @@ -21,7 +21,9 @@ def epoch_info end def estimated_epoch_time - tip_block.difficulty * tip_block.length / hash_rate + if hash_rate.present? + (tip_block.difficulty * tip_block.length / hash_rate).truncate(6) + end end def transactions_last_24hrs @@ -35,7 +37,7 @@ def transactions_count_per_minute(interval = 100) transactions_count = Block.where(number: start_block_number..tip_block_number).sum(:ckb_transactions_count) - transactions_count / (total_block_time(timestamps) / 1000 / 60) + (transactions_count / (total_block_time(timestamps) / 1000 / 60)).truncate(3) end def current_epoch_difficulty @@ -57,7 +59,7 @@ def hash_rate(block_number = tip_block_number) total_difficulties = blocks.flat_map { |block| [block, *block.uncle_blocks] }.reduce(0) { |sum, block| sum + block.difficulty } total_time = blocks.first.timestamp - blocks.last.timestamp - total_difficulties.to_d / total_time + (total_difficulties.to_d / total_time).truncate(6) end def miner_ranking diff --git a/app/models/udt_account.rb b/app/models/udt_account.rb index 994535073..6e3ba7153 100644 --- a/app/models/udt_account.rb +++ b/app/models/udt_account.rb @@ -15,7 +15,7 @@ class UdtAccount < ApplicationRecord scope :published, -> { where(published: true) } def udt_icon_file - Rails.cache.realize([self.class.name, "udt_icon_file", id], race_condition_ttl: 3.seconds, expires_in: 1.days) do + Rails.cache.realize([self.class.name, "udt_icon_file", id], race_condition_ttl: 3.seconds, expires_in: 1.day) do udt.icon_file end end diff --git a/app/serializers/daily_statistic_serializer.rb b/app/serializers/daily_statistic_serializer.rb index abe1715b8..f0e773a60 100644 --- a/app/serializers/daily_statistic_serializer.rb +++ b/app/serializers/daily_statistic_serializer.rb @@ -27,11 +27,15 @@ class DailyStatisticSerializer attribute :avg_hash_rate, if: Proc.new { |_record, params| params && params[:indicator].include?("avg_hash_rate") - } + } do |object| + object.avg_hash_rate.to_d.truncate(6).to_s + end attribute :avg_difficulty, if: Proc.new { |_record, params| params && params[:indicator].include?("avg_difficulty") - } + } do |object| + object.avg_difficulty.to_d.truncate(3).to_s + end attribute :uncle_rate, if: Proc.new { |_record, params| params && params[:indicator].include?("uncle_rate") @@ -86,4 +90,38 @@ class DailyStatisticSerializer } do |object| object.nodes_count.to_s end + + attribute :circulating_supply, if: Proc.new { |_record, params| + params && params[:indicator].include?("circulating_supply") + } + + attribute :burnt, if: Proc.new { |_record, params| + params && params[:indicator].include?("burnt") + } do |object| + object.burnt.to_s + end + + attribute :locked_capacity, if: Proc.new { |_record, params| + params && params[:indicator].include?("locked_capacity") + } do |object| + object.locked_capacity.to_s + end + + attribute :treasury_amount, if: Proc.new { |_record, params| + params && params[:indicator].include?("treasury_amount") + } + + attribute :mining_reward, if: Proc.new { |_record, params| + params && params[:indicator].include?("mining_reward") + } + + attribute :deposit_compensation, if: Proc.new { |_record, params| + params && params[:indicator].include?("deposit_compensation") + } + + attribute :liquidity, if: Proc.new { |_record, params| + params && params[:indicator].include?("liquidity") + } do |object| + object.liquidity.to_s + end end diff --git a/app/serializers/dao_depositor_serializer.rb b/app/serializers/dao_depositor_serializer.rb index df52fc3c7..472f986ee 100644 --- a/app/serializers/dao_depositor_serializer.rb +++ b/app/serializers/dao_depositor_serializer.rb @@ -5,6 +5,6 @@ class DaoDepositorSerializer object.dao_deposit.to_s end attribute :average_deposit_time do |object| - object.average_deposit_time.to_s + object.average_deposit_time&.truncate(3).to_s end end diff --git a/app/serializers/distribution_data_serializer.rb b/app/serializers/distribution_data_serializer.rb index 9179ddbbd..136a5c0a1 100644 --- a/app/serializers/distribution_data_serializer.rb +++ b/app/serializers/distribution_data_serializer.rb @@ -48,4 +48,8 @@ class DistributionDataSerializer } do |object| object.transaction_propagation_delay_history end + + attribute :miner_address_distribution, if: Proc.new { |_record, params| + params && params[:indicator].include?("miner_address_distribution") + } end diff --git a/app/serializers/epoch_statistic_serializer.rb b/app/serializers/epoch_statistic_serializer.rb index ba5e2ce9a..3fab6a931 100644 --- a/app/serializers/epoch_statistic_serializer.rb +++ b/app/serializers/epoch_statistic_serializer.rb @@ -11,7 +11,9 @@ class EpochStatisticSerializer attribute :uncle_rate, if: Proc.new { |_record, params| params && params[:indicator].include?("uncle_rate") - } + } do |object| + object.uncle_rate.to_d.truncate(5).to_s + end attribute :hash_rate, if: Proc.new { |_record, params| params && params[:indicator].include?("hash_rate") diff --git a/app/serializers/monetary_data_serializer.rb b/app/serializers/monetary_data_serializer.rb new file mode 100644 index 000000000..a02e0b8bd --- /dev/null +++ b/app/serializers/monetary_data_serializer.rb @@ -0,0 +1,25 @@ +class MonetaryDataSerializer + include FastJsonapi::ObjectSerializer + + attribute :nominal_apc, if: Proc.new { |_record, params| + params && params[:indicator].include?("nominal_apc") + } do |object, params| + if rs = params[:indicator].match(/(\d+)/) + object.nominal_apc(rs[1].to_i).map(&:to_s) + else + object.nominal_apc.map(&:to_s) + end + end + + attribute :nominal_inflation_rate, if: Proc.new { |_record, params| + params && params[:indicator].include?("nominal_inflation_rate") + } do |object| + object.nominal_inflation_rate.map(&:to_s) + end + + attribute :real_inflation_rate, if: Proc.new { |_record, params| + params && params[:indicator].include?("real_inflation_rate") + } do |object| + object.real_inflation_rate.map(&:to_s) + end +end diff --git a/app/services/charts/daily_statistic_generator.rb b/app/services/charts/daily_statistic_generator.rb index 7678ef816..9f358d21d 100644 --- a/app/services/charts/daily_statistic_generator.rb +++ b/app/services/charts/daily_statistic_generator.rb @@ -29,14 +29,19 @@ def call avg_difficulty: avg_difficulty, uncle_rate: uncle_rate, total_depositors_count: total_depositors_count, address_balance_distribution: address_balance_distribution, total_tx_fee: total_tx_fee, occupied_capacity: occupied_capacity, daily_dao_deposit: daily_dao_deposit, daily_dao_depositors_count: daily_dao_depositors_count, daily_dao_withdraw: daily_dao_withdraw, - total_supply: total_supply, circulation_ratio: circulation_ratio, block_time_distribution: block_time_distribution, - epoch_time_distribution: epoch_time_distribution, epoch_length_distribution: epoch_length_distribution, average_block_time: average_block_time) + total_supply: total_supply, circulating_supply: circulating_supply, circulation_ratio: circulation_ratio, block_time_distribution: block_time_distribution, + epoch_time_distribution: epoch_time_distribution, epoch_length_distribution: epoch_length_distribution, average_block_time: average_block_time, locked_capacity: locked_capacity) end private attr_reader :datetime, :from_scratch + def locked_capacity + market_data = MarketData.new(tip_block_number: current_tip_block.number) + market_data.ecosystem_locked + market_data.team_locked + market_data.private_sale_locked + market_data.founding_partners_locked + market_data.foundation_reserve_locked + market_data.bug_bounty_locked + end + def average_block_time Block.connection.select_all(avg_block_time_rolling_by_hour_sql).to_a.map do |item| { timestamp: item["stat_timestamp"].to_i, avg_block_time_daily: item["avg_bt1"], avg_block_time_weekly: item["avg_bt2"] } @@ -62,7 +67,7 @@ def epoch_length_distribution interval = 499 start_epoch_number = [0, tip_epoch_number - interval].max - ranges.each_with_index.map { |range, index| + ranges.each_with_index.map { |range, _index| epoch_count = ::EpochStatistic.where("epoch_number >= ? and epoch_number <= ?", start_epoch_number, tip_epoch_number).where("epoch_length > ? and epoch_length <= ?", range[0], range[1]).count [range[1], epoch_count] @@ -104,11 +109,11 @@ def block_time_distribution end def circulating_supply - MarketData.new("circulating_supply", current_tip_block.number).call + MarketData.new(indicator: "circulating_supply", tip_block_number: current_tip_block.number, unit: "shannon").call end def circulation_ratio - total_dao_deposit / 10**8 / circulating_supply + total_dao_deposit / circulating_supply end def total_supply @@ -204,7 +209,7 @@ def avg_difficulty end def total_difficulties_for_the_day - @total_difficulties ||= + @total_difficulties_for_the_day ||= epoch_numbers_for_the_day.reduce(0) do |memo, epoch_number| first_block_of_the_epoch = Block.created_after(started_at).created_before(ended_at).where(epoch: epoch_number).recent.last last_block_of_the_epoch = Block.created_after(started_at).created_before(ended_at).where(epoch: epoch_number).recent.first @@ -318,7 +323,7 @@ def unmade_dao_interests tip_dao = current_tip_block.dao parse_dao = CkbUtils.parse_dao(dao) tip_parse_dao = CkbUtils.parse_dao(tip_dao) - memo + (cell_output.capacity * tip_parse_dao.ar_i / parse_dao.ar_i) - cell_output.capacity + memo + (cell_output.capacity.to_i * tip_parse_dao.ar_i / parse_dao.ar_i) - cell_output.capacity.to_i end end end @@ -343,7 +348,7 @@ def average_deposit_time total_deposits = interest_bearing_deposits + uninterest_bearing_deposits return 0 if total_deposits.zero? - (sum_interest_bearing + sum_uninterest_bearing) / total_deposits + ((sum_interest_bearing + sum_uninterest_bearing) / total_deposits).truncate(3) end def treasury_amount @@ -358,12 +363,18 @@ def yesterday_daily_statistic @yesterday_daily_statistic ||= begin yesterday_statistic = ::DailyStatistic.find_by(created_at_unixtimestamp: to_be_counted_date.yesterday.beginning_of_day.to_i) - if to_be_counted_date.beginning_of_day.to_i == Time.at(GENESIS_TIMESTAMP / 1000).beginning_of_day.to_i + if to_be_counted_date.beginning_of_day.to_i == Time.at(GENESIS_TIMESTAMP / 1000).in_time_zone.beginning_of_day.to_i || aggron_first_day? OpenStruct.new(addresses_count: 0, total_dao_deposit: 0, dao_depositors_count: 0, unclaimed_compensation: 0, claimed_compensation: 0, average_deposit_time: 0, mining_reward: 0, deposit_compensation: 0, treasury_amount: 0, total_depositors_count: 0, live_cells_count: 0, dead_cells_count: 0, occupied_capacity: 0) else yesterday_statistic end end end + + def aggron_first_day? + genesis_block_timestamp = Block.find_by(number: 0).timestamp + + ENV["CKB_NET_MODE"] == "testnet" && to_be_counted_date.beginning_of_day.to_i == Time.at(genesis_block_timestamp / 1000).in_time_zone.beginning_of_day.to_i + end end end diff --git a/app/utils/ckb_utils.rb b/app/utils/ckb_utils.rb index 581c1d813..0875537f5 100644 --- a/app/utils/ckb_utils.rb +++ b/app/utils/ckb_utils.rb @@ -264,7 +264,7 @@ def self.parse_dao(dao) def self.parse_udt_cell_data(data) return if data.delete_prefix("0x") == "" - [data.delete_prefix("0x")].pack("H*")[0..15].reverse.unpack1("B*").to_i(2) + CKB::Utils.sudt_amount(data) end def self.time_in_milliseconds(time) diff --git a/app/workers/address_average_deposit_time_generator.rb b/app/workers/address_average_deposit_time_generator.rb index 1a9dfac4f..105f53891 100644 --- a/app/workers/address_average_deposit_time_generator.rb +++ b/app/workers/address_average_deposit_time_generator.rb @@ -33,6 +33,6 @@ def cal_average_deposit_time(address) memo + nervos_dao_deposit_cell.capacity * (ended_at - nervos_dao_deposit_cell.block_timestamp) / milliseconds_in_day end - (sum_interest_bearing + sum_uninterest_bearing) / (interest_bearing_deposits + uninterest_bearing_deposits) + ((sum_interest_bearing + sum_uninterest_bearing) / (interest_bearing_deposits + uninterest_bearing_deposits)).truncate(6) end end diff --git a/config/routes.rb b/config/routes.rb index bf31a5ea7..050022217 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -42,6 +42,7 @@ resources :udt_transactions, only: :show resources :address_udt_transactions, only: :show resources :distribution_data, only: :show + resources :monetary_data, only: :show end end diff --git a/db/migrate/20200525100826_add_locked_capacity_to_daily_statistic.rb b/db/migrate/20200525100826_add_locked_capacity_to_daily_statistic.rb new file mode 100644 index 000000000..0b29b1c9b --- /dev/null +++ b/db/migrate/20200525100826_add_locked_capacity_to_daily_statistic.rb @@ -0,0 +1,5 @@ +class AddLockedCapacityToDailyStatistic < ActiveRecord::Migration[6.0] + def change + add_column :daily_statistics, :locked_capacity, :decimal, precision: 30 + end +end diff --git a/db/schema.rb b/db/schema.rb index 2b0457601..52ae6c958 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_05_13_032346) do +ActiveRecord::Schema.define(version: 2020_05_25_100826) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -218,6 +218,7 @@ t.jsonb "average_block_time" t.jsonb "nodes_distribution" t.integer "nodes_count" + t.decimal "locked_capacity", precision: 30 end create_table "dao_contracts", force: :cascade do |t| diff --git a/doc/api.raml b/doc/api.raml index 5c3944e3f..0cdfef5b0 100644 --- a/doc/api.raml +++ b/doc/api.raml @@ -647,6 +647,27 @@ types: }, "circulation_ratio": { "type": "string" + }, + "circulating_supply": { + "type": "string" + }, + "burnt": { + "type": "string" + }, + "locked_capacity": { + "type": "string" + }, + "treasury_amount": { + "type": "string" + }, + "mining_reward": { + "type": "string" + }, + "deposit_compensation": { + "type": "string" + }, + "liquidity": { + "type": "string" } } } @@ -660,6 +681,15 @@ types: } } + monetary_data_attributes: { + type: object, + properties: { + "nominal_apc": { + type: "string[]", + } + } + } + block_statistic_attributes: { type: object, properties: { @@ -1029,6 +1059,15 @@ types: } } + monetary_data_response: { + type: object, + properties: { + "data": { + "type": monetary_data_attributes + } + } + } + block_statistic_response: { type: object, properties: { @@ -3471,6 +3510,62 @@ types: ] } +/monetary_data: + /{indicator}: + uriParameters: + indicator: + description: The indicator name + required: true + type: string + get: + description: Returns the monetary data + responses: + 200: + body: + application/vnd.api+json: + type: monetary_data_response + examples: + nominal_apc: | + { + "id": "1", + "type": "monetary_data_data", + "attributes": { + "nominal_apc": [ + "4.0", "3.94574599", "3.89294403", "3.84153661", "3.79146919" + ] + } + }, + inflation_rate: | + { + "id": "1", + "type": "monetary_data_data", + "attributes": { + "inflation_rate": { + "nominal_apc": ["4.0", "3.94574599", "3.89294403", "3.84153661", "3.79146919"], + "nominal_inflation_rate": ["16.5", "16.27620221", "16.05839416", "15.84633853"], + "real_inflation_rate": ["12.5", "12.33045622", "12.16545012", "12.00480192"] + } + } + } + 404: + body: + application/vnd.api+json: + type: error_response + example: | + { + "message": "Record Not Found", + "errors": [ + { + "id": "ActiveRecord::RecordNotFound", + "code": "1141", + "status": "404", + "title": "Record not fund", + "detail": "No matching address record were found", + "href": "https://nervosnetwork.github.io/ckb-explorer/public/api_doc.html" + } + ] + } + /block_statistics: /{indicator}: uriParameters: diff --git a/lib/tasks/migration/fill_locked_capacity_to_daily_statistics.rake b/lib/tasks/migration/fill_locked_capacity_to_daily_statistics.rake new file mode 100644 index 000000000..03e28aac4 --- /dev/null +++ b/lib/tasks/migration/fill_locked_capacity_to_daily_statistics.rake @@ -0,0 +1,21 @@ +namespace :migration do + task fill_locked_capacity_to_daily_statistics: :environment do + progress_bar = ProgressBar.create({ + total: DailyStatistic.count, + format: "%e %B %p%% %c/%C" + }) + + values = + DailyStatistic.order(:created_at_unixtimestamp).all.map do |daily_statistic| + progress_bar.increment + to_be_counted_date = Time.at(daily_statistic.created_at_unixtimestamp) + daily_statistic_generator = Charts::DailyStatisticGenerator.new(to_be_counted_date) + + { id: daily_statistic.id, locked_capacity: daily_statistic_generator.send(:locked_capacity), created_at: daily_statistic.created_at, updated_at: Time.current } + end + + DailyStatistic.upsert_all(values) + + puts "done" + end +end diff --git a/lib/tasks/migration/update_daily_statistic_interests_related_info.rake b/lib/tasks/migration/update_daily_statistic_interests_related_info.rake new file mode 100644 index 000000000..c8c812391 --- /dev/null +++ b/lib/tasks/migration/update_daily_statistic_interests_related_info.rake @@ -0,0 +1,25 @@ +namespace :migration do + desc "Usage: RAILS_ENV=production bundle exec rake migration:update_daily_statistic_interests_related_info" + task update_daily_statistic_interests_related_info: :environment do + progress_bar = ProgressBar.create({ total: DailyStatistic.count, format: "%e %B %p%% %c/%C" }) + + values = [] + DailyStatistic.all.each do |daily_statistic| + to_be_counted_date = Time.at(daily_statistic.created_at_unixtimestamp) + daily_statistic_generator = Charts::DailyStatisticGenerator.new(to_be_counted_date) + unclaimed_compensation = daily_statistic_generator.send(:unclaimed_compensation) + treasury_amount = daily_statistic_generator.send(:treasury_amount) + deposit_compensation = unclaimed_compensation + daily_statistic_generator.send(:claimed_compensation) + total_supply = daily_statistic_generator.send(:total_supply) + values << { id: daily_statistic.id, created_at: daily_statistic.created_at, + updated_at: Time.current, unclaimed_compensation: unclaimed_compensation, treasury_amount: treasury_amount, + deposit_compensation: deposit_compensation, total_supply: total_supply } + + progress_bar.increment + end + + DailyStatistic.upsert_all(values) + + puts "done" + end +end diff --git a/public/api_doc.html b/public/api_doc.html index d2e51ce0b..67b351a84 100644 --- a/public/api_doc.html +++ b/public/api_doc.html @@ -1981,7 +1981,7 @@ } ] } -