From 91efc8541bf6159d2e06bfd1108faa759f792b7c Mon Sep 17 00:00:00 2001 From: classicalliu Date: Mon, 3 Sep 2018 14:40:54 +0800 Subject: [PATCH] cache validator counter --- app/controllers/api/statistics_controller.rb | 5 ++-- app/models/block.rb | 10 +++++++ app/models/validator_cache.rb | 22 ++++++++++++++++ .../20180903024536_create_validator_caches.rb | 23 ++++++++++++++++ db/schema.rb | 10 ++++++- spec/factories/validator_caches.rb | 5 ++++ spec/models/block_spec.rb | 18 +++++++++++++ spec/models/validator_cache_spec.rb | 26 +++++++++++++++++++ 8 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 app/models/validator_cache.rb create mode 100644 db/migrate/20180903024536_create_validator_caches.rb create mode 100644 spec/factories/validator_caches.rb create mode 100644 spec/models/validator_cache_spec.rb diff --git a/app/controllers/api/statistics_controller.rb b/app/controllers/api/statistics_controller.rb index 198bed4..344249b 100644 --- a/app/controllers/api/statistics_controller.rb +++ b/app/controllers/api/statistics_controller.rb @@ -30,8 +30,9 @@ def index # } # ] def proposals - result = Block.where.not(block_number: 0).group("header ->> 'proposer'").count - .map { |k, v| { validator: k, count: v } } + # result = Block.where.not(block_number: 0).group("header ->> 'proposer'").count + # .map { |k, v| { validator: k, count: v } } + result = ValidatorCache.all.map { |c| { validator: c.name, count: c.counter } } render json: { result: result diff --git a/app/models/block.rb b/app/models/block.rb index 9243250..f832e1b 100644 --- a/app/models/block.rb +++ b/app/models/block.rb @@ -9,10 +9,20 @@ class Block < ApplicationRecord store_accessor :header, :timestamp + after_create :increase_validator_count + # get current last block number in database # # @return [Integer, nil] the current last block number or nil if no block found in db. def self.current_block_number Block.order(block_number: :desc).first&.block_number end + + private + + # increase validator count after block create + def increase_validator_count + return if self.block_number.zero? + ValidatorCache.increase(self.header["proposer"]) + end end diff --git a/app/models/validator_cache.rb b/app/models/validator_cache.rb new file mode 100644 index 0000000..0dcb5e5 --- /dev/null +++ b/app/models/validator_cache.rb @@ -0,0 +1,22 @@ +class ValidatorCache < ApplicationRecord + validates :name, presence: true, uniqueness: true + + # increase a validator's count + # + # @param name [String] Block header proposer + # @return [void] + def self.increase(name) + # add transaction for lock cache + ApplicationRecord.transaction do + return if name.blank? + cache = ValidatorCache.find_by(name: name) + if cache.nil? + ValidatorCache.create(name: name, counter: 1) + else + # lock it + cache.lock! + cache.update!(counter: cache.counter + 1) + end + end + end +end diff --git a/db/migrate/20180903024536_create_validator_caches.rb b/db/migrate/20180903024536_create_validator_caches.rb new file mode 100644 index 0000000..139dee3 --- /dev/null +++ b/db/migrate/20180903024536_create_validator_caches.rb @@ -0,0 +1,23 @@ +class CreateValidatorCaches < ActiveRecord::Migration[5.2] + def change + create_table :validator_caches do |t| + t.string :name, null: false, index: { unique: true } + t.integer :counter + + t.timestamps + end + + reversible do |dir| + dir.up do + # create validator cache for present blocks + ApplicationRecord.transaction do + Block.where.not(block_number: 0).group("header ->> 'proposer'").count.each do |k, v| + cache = ValidatorCache.find_or_create_by(name: k) + cache.lock! + cache.update(counter: v) + end + end + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 69a0e79..73d5705 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: 2018_08_30_054052) do +ActiveRecord::Schema.define(version: 2018_09_03_024536) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -83,4 +83,12 @@ t.index ["cita_hash"], name: "index_transactions_on_cita_hash", unique: true end + create_table "validator_caches", force: :cascade do |t| + t.string "name", null: false + t.integer "counter" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["name"], name: "index_validator_caches_on_name", unique: true + end + end diff --git a/spec/factories/validator_caches.rb b/spec/factories/validator_caches.rb new file mode 100644 index 0000000..c77bb09 --- /dev/null +++ b/spec/factories/validator_caches.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :validator_cache, class: 'ValidatorCache' do + name "0x91827976af27e1fd405469b00dc8d3b0ea2203f6" + end +end diff --git a/spec/models/block_spec.rb b/spec/models/block_spec.rb index 1c81847..547df44 100644 --- a/spec/models/block_spec.rb +++ b/spec/models/block_spec.rb @@ -52,4 +52,22 @@ expect(Block.current_block_number).to eq block.block_number end end + + context "after create" do + context "increase_validator_count" do + it "not cache if block_number.zero?" do + block = create :block_zero, block_number: 0 + proposer = block.header['proposer'] + expect(proposer.blank?).not_to be true + expect(ValidatorCache.exists?(name: proposer)).to be false + end + + it "cache if block_number not eq zero" do + block = create :block_one, block_number: 1 + proposer = block.header["proposer"] + expect(proposer.blank?).not_to be true + expect(ValidatorCache.find_by(name: proposer).counter).to eq 1 + end + end + end end diff --git a/spec/models/validator_cache_spec.rb b/spec/models/validator_cache_spec.rb new file mode 100644 index 0000000..fbfb4ad --- /dev/null +++ b/spec/models/validator_cache_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe ValidatorCache, type: :model do + let(:proposer) { attributes_for(:validator_cache)[:name] } + + context "increase" do + it "counter be 1 if not exist" do + expect(ValidatorCache.exists?(name: proposer)).to be false + expect { + ValidatorCache.increase(proposer) + }.to change { ValidatorCache.count }.by(1) + cache = ValidatorCache.find_by(name: proposer) + expect(cache.counter).to eq 1 + end + + it "counter add 1 if exist" do + counter = 5 + create :validator_cache, counter: counter + expect { + ValidatorCache.increase(proposer) + }.to change { ValidatorCache.count }.by(0) + cache = ValidatorCache.find_by(name: proposer) + expect(cache.counter).to eq (counter + 1) + end + end +end