From a18ef6a11dfa80a2158181e15538fe9ffa3dfa93 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Thu, 12 Dec 2019 21:48:26 +0800 Subject: [PATCH 01/77] test: ckb transactions index action media type --- .../v1/ckb_transactions_controller_test.rb | 42 +++++++++++++++++++ test/test_helper.rb | 3 -- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/test/controllers/api/v1/ckb_transactions_controller_test.rb b/test/controllers/api/v1/ckb_transactions_controller_test.rb index f033810d5..d20c0b595 100644 --- a/test/controllers/api/v1/ckb_transactions_controller_test.rb +++ b/test/controllers/api/v1/ckb_transactions_controller_test.rb @@ -128,6 +128,48 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest assert_equal 15, json["data"].dig("attributes", "display_outputs").count assert_equal [false], json["data"].dig("attributes", "display_outputs").map { |input| input.key?("from_cellbase") }.uniq end + + test "should get success code when call index" do + valid_get api_v1_ckb_transactions_url + + assert_response :success + end + + test "should set right content type when call index" do + valid_get api_v1_ckb_transactions_url + + assert_equal "application/vnd.api+json", response.media_type + end + + test "should respond with 415 Unsupported Media Type when call index and Content-Type is wrong" do + get api_v1_ckb_transactions_url, headers: { "Content-Type": "text/plain" } + + assert_equal 415, response.status + end + + test "should respond with error object when call index and Content-Type is wrong" do + error_object = Api::V1::Exceptions::WrongContentTypeError.new + response_json = RequestErrorSerializer.new([error_object], message: error_object.title).serialized_json + + get api_v1_ckb_transactions_url, headers: { "Content-Type": "text/plain" } + + assert_equal response_json, response.body + end + + test "should respond with 406 Not Acceptable when call index and Accept is wrong" do + get api_v1_ckb_transactions_url, headers: { "Content-Type": "application/vnd.api+json", "Accept": "application/json" } + + assert_equal 406, response.status + end + + test "should respond with error object when call index and Accept is wrong" do + error_object = Api::V1::Exceptions::WrongAcceptError.new + response_json = RequestErrorSerializer.new([error_object], message: error_object.title).serialized_json + + get api_v1_ckb_transactions_url, headers: { "Content-Type": "application/vnd.api+json", "Accept": "application/json" } + + assert_equal response_json, response.body + end end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index e0a4a7932..89241dce5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -260,9 +260,6 @@ class TestCase # fixtures :all include FactoryBot::Syntax::Methods include ::RequestHelpers - if ENV["CI"] != "true" - parallelize(workers: 2, with: :threads) - end # Add more helper methods to be used by all tests here... def before_setup From e71fef76e4185bf7f6eb673e1c348ff231ec64a1 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Thu, 12 Dec 2019 21:48:53 +0800 Subject: [PATCH 02/77] feat: add index action to ckb transactions controller --- app/controllers/api/v1/ckb_transactions_controller.rb | 4 ++++ config/routes.rb | 1 + 2 files changed, 5 insertions(+) diff --git a/app/controllers/api/v1/ckb_transactions_controller.rb b/app/controllers/api/v1/ckb_transactions_controller.rb index fb3027641..2279d7c99 100644 --- a/app/controllers/api/v1/ckb_transactions_controller.rb +++ b/app/controllers/api/v1/ckb_transactions_controller.rb @@ -3,6 +3,10 @@ module V1 class CkbTransactionsController < ApplicationController before_action :validate_query_params, only: :show + def index + render json: {} + end + def show ckb_transaction = CkbTransaction.cached_find(params[:id]) diff --git a/config/routes.rb b/config/routes.rb index 027ebd8de..70f5744c9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,6 +17,7 @@ resources :block_transactions, only: :show resources :addresses, only: :show get "/transactions/:id", to: "ckb_transactions#show", as: "ckb_transaction" + get "/transactions", to: "ckb_transactions#index", as: "ckb_transactions" resources :cell_input_lock_scripts, only: :show resources :cell_input_type_scripts, only: :show resources :cell_input_data, only: :show From 63480f9394dede9c710e2deaec708ffc751852cc Mon Sep 17 00:00:00 2001 From: shaojunda Date: Thu, 12 Dec 2019 21:59:41 +0800 Subject: [PATCH 03/77] test: ckb transactions controller's index action --- .env | 1 + .../v1/ckb_transactions_controller_test.rb | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/.env b/.env index 24bc86fef..4c47524db 100644 --- a/.env +++ b/.env @@ -29,3 +29,4 @@ BLOCK_PROCESS_LOOP_INTERVAL="1" DEFAULT_EPOCH_REWARD="1_917_808_21917808" CKB_NET_MODE="mainnet" HOMEPAGE_BLOCK_RECORDS_COUNT="15" +HOMEPAGE_TRANSACTIONS_RECORDS_COUNT="15" diff --git a/test/controllers/api/v1/ckb_transactions_controller_test.rb b/test/controllers/api/v1/ckb_transactions_controller_test.rb index d20c0b595..2c0e7609a 100644 --- a/test/controllers/api/v1/ckb_transactions_controller_test.rb +++ b/test/controllers/api/v1/ckb_transactions_controller_test.rb @@ -170,6 +170,62 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest assert_equal response_json, response.body end + + test "should get serialized objects" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 15, block: block) + + ckb_transactions = CkbTransaction.recent.limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) + + valid_get api_v1_ckb_transactions_url + + assert_equal CkbTransactionSerializer.new(ckb_transactions).serialized_json, response.body + end + + test "serialized objects should in reverse order of timestamp" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 15, block: block) + + valid_get api_v1_ckb_transactions_url + + first_ckb_transaction = json["data"].first + last_ckb_transaction = json["data"].last + + assert_operator first_ckb_transaction.dig("attributes", "block_timestamp"), :>, last_ckb_transaction.dig("attributes", "block_timestamp") + end + + test "should contain right keys in the serialized object" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 15, block: block) + + valid_get api_v1_ckb_transactions_url + + response_ckb_transaction = json["data"].first + assert_equal %w(block_number transaction_hash block_timestamp transaction_fee version display_inputs display_outputs is_cellbase income witnesses cell_deps header_deps).sort, response_ckb_transaction["attributes"].keys.sort + end + + test "should return the corresponding number of ckb transactions " do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 30, block: block) + + valid_get api_v1_ckb_transactions_url + + ckb_transactions = CkbTransaction.order(block_timestamp: :desc).limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) + response_ckb_transaction = CkbTransactionSerializer.new(ckb_transactions).serialized_json + assert_equal response_ckb_transaction, response.body + assert_equal 15, json["data"].size + end + + test "should return empty array when there is no ckb_transactions" do + ckb_transactions = CkbTransaction.order(block_timestamp: :desc).limit(15) + + valid_get api_v1_ckb_transactions_url + + response_ckb_transaction = CkbTransactionSerializer.new(ckb_transactions).serialized_json + + assert_equal [], json["data"] + assert_equal response_ckb_transaction, response.body + end end end end From 26e5a36ed807986bf9d6f28667580b375d993529 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Thu, 12 Dec 2019 22:04:49 +0800 Subject: [PATCH 04/77] feat: implement ckb transactions index action --- app/controllers/api/v1/ckb_transactions_controller.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/ckb_transactions_controller.rb b/app/controllers/api/v1/ckb_transactions_controller.rb index 2279d7c99..8e28c9028 100644 --- a/app/controllers/api/v1/ckb_transactions_controller.rb +++ b/app/controllers/api/v1/ckb_transactions_controller.rb @@ -4,7 +4,8 @@ class CkbTransactionsController < ApplicationController before_action :validate_query_params, only: :show def index - render json: {} + ckb_transactions = CkbTransaction.recent.limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) + render json: CkbTransactionSerializer.new(ckb_transactions) end def show From 8d729d755d15b89ebcca39395c483d6fc5869ad9 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 16:46:27 +0800 Subject: [PATCH 05/77] feat: add block list serializer --- app/controllers/api/v1/blocks_controller.rb | 2 +- app/serializers/block_list_serializer.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 app/serializers/block_list_serializer.rb diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb index 233c70567..9f0844f70 100644 --- a/app/controllers/api/v1/blocks_controller.rb +++ b/app/controllers/api/v1/blocks_controller.rb @@ -13,7 +13,7 @@ def index options = FastJsonapi::PaginationMetaGenerator.new(request: request, records: blocks, page: @page, page_size: @page_size).call end - render json: BlockSerializer.new(blocks, options) + render json: BlockListSerializer.new(blocks, options) end def show diff --git a/app/serializers/block_list_serializer.rb b/app/serializers/block_list_serializer.rb new file mode 100644 index 000000000..96c5b7171 --- /dev/null +++ b/app/serializers/block_list_serializer.rb @@ -0,0 +1,18 @@ +class BlockListSerializer + include FastJsonapi::ObjectSerializer + + attributes :miner_hash + + attribute :number do |object| + object.number.to_s + end + attribute :timestamp do |object| + object.timestamp.to_s + end + attribute :reward do |object| + object.reward.to_s + end + attribute :transactions_count do |object| + object.ckb_transactions_count.to_s + end +end From 93f437b2e965844f074ddeb2f8fc933a70ec6efa Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 16:46:38 +0800 Subject: [PATCH 06/77] chore: adjust tests --- .../controllers/api/v1/blocks_controller_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/controllers/api/v1/blocks_controller_test.rb b/test/controllers/api/v1/blocks_controller_test.rb index 7cb72d1f1..c7f1d6fcc 100644 --- a/test/controllers/api/v1/blocks_controller_test.rb +++ b/test/controllers/api/v1/blocks_controller_test.rb @@ -52,7 +52,7 @@ class BlocksControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_blocks_url - assert_equal BlockSerializer.new(blocks, {}).serialized_json, response.body + assert_equal BlockListSerializer.new(blocks, {}).serialized_json, response.body end test "serialized objects should in reverse order of timestamp" do @@ -72,7 +72,7 @@ class BlocksControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_blocks_url response_block = json["data"].first - assert_equal %w(block_hash number transactions_count proposals_count uncles_count uncle_block_hashes reward total_transaction_fee cell_consumed total_cell_capacity miner_hash timestamp difficulty version nonce epoch start_number length transactions_root reward_status received_tx_fee received_tx_fee_status block_index_in_epoch).sort, response_block["attributes"].keys.sort + assert_equal %w(number transactions_count reward miner_hash timestamp ).sort, response_block["attributes"].keys.sort end test "should return error object when page param is invalid" do @@ -123,10 +123,10 @@ class BlocksControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_blocks_url, params: { page: page, page_size: page_size } - block_hashes = Block.recent.map(&:block_hash) - search_result_block_hashes = json["data"].map { |ckb_transaction| ckb_transaction.dig("attributes", "block_hash") } + block_hashes = Block.recent.map(&:number).map(&:to_s) + search_result_block_numbers = json["data"].map { |block| block.dig("attributes", "number")} - assert_equal block_hashes, search_result_block_hashes + assert_equal block_hashes, search_result_block_numbers end test "should return corresponding page's records when page is set and page_size is not set" do @@ -136,7 +136,7 @@ class BlocksControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_blocks_url, params: { page: page } - response_blocks = BlockSerializer.new(blocks, {}).serialized_json + response_blocks = BlockListSerializer.new(blocks, {}).serialized_json assert_equal response_blocks, response.body assert_equal 15, json["data"].size @@ -148,7 +148,7 @@ class BlocksControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_blocks_url, params: { page_size: 12 } blocks = Block.order(timestamp: :desc).limit(ENV["HOMEPAGE_BLOCK_RECORDS_COUNT"].to_i) - response_blocks = BlockSerializer.new(blocks, {}).serialized_json + response_blocks = BlockListSerializer.new(blocks, {}).serialized_json assert_equal response_blocks, response.body assert_equal 15, json["data"].size end @@ -162,7 +162,7 @@ class BlocksControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_blocks_url, params: { page: page, page_size: page_size } options = FastJsonapi::PaginationMetaGenerator.new(request: request, records: blocks, page: page, page_size: page_size).call - response_blocks = BlockSerializer.new(blocks, options).serialized_json + response_blocks = BlockListSerializer.new(blocks, options).serialized_json assert_equal response_blocks, response.body end From 2f04c6222892f284fc4d70443e3d0d268666e346 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 20:50:47 +0800 Subject: [PATCH 07/77] feat: add live_cell_changes to block and ckb_transaction --- app/models/block.rb | 1 + app/models/ckb_transaction.rb | 29 ++++++++++--------- ...ll_changes_to_block_and_ckb_transaction.rb | 6 ++++ db/schema.rb | 4 ++- 4 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 db/migrate/20191225110229_add_live_cell_changes_to_block_and_ckb_transaction.rb diff --git a/app/models/block.rb b/app/models/block.rb index feef47fe9..2515f1b5d 100644 --- a/app/models/block.rb +++ b/app/models/block.rb @@ -131,6 +131,7 @@ def invalid! # length :decimal(30, ) default(0) # uncles_count :integer # compact_target :decimal(20, ) +# live_cell_changes :integer # # Indexes # diff --git a/app/models/ckb_transaction.rb b/app/models/ckb_transaction.rb index a16904a91..e019f4d6e 100644 --- a/app/models/ckb_transaction.rb +++ b/app/models/ckb_transaction.rb @@ -117,20 +117,21 @@ def recover_dead_cell # # Table name: ckb_transactions # -# id :bigint not null, primary key -# tx_hash :binary -# deps :jsonb -# block_id :bigint -# block_number :decimal(30, ) -# block_timestamp :decimal(30, ) -# transaction_fee :decimal(30, ) -# version :integer -# created_at :datetime not null -# updated_at :datetime not null -# is_cellbase :boolean default(FALSE) -# header_deps :binary -# cell_deps :jsonb -# witnesses :jsonb +# id :bigint not null, primary key +# tx_hash :binary +# deps :jsonb +# block_id :bigint +# block_number :decimal(30, ) +# block_timestamp :decimal(30, ) +# transaction_fee :decimal(30, ) +# version :integer +# created_at :datetime not null +# updated_at :datetime not null +# is_cellbase :boolean default(FALSE) +# witnesses :jsonb +# header_deps :binary +# cell_deps :jsonb +# live_cell_changes :integer # # Indexes # diff --git a/db/migrate/20191225110229_add_live_cell_changes_to_block_and_ckb_transaction.rb b/db/migrate/20191225110229_add_live_cell_changes_to_block_and_ckb_transaction.rb new file mode 100644 index 000000000..78c6c585d --- /dev/null +++ b/db/migrate/20191225110229_add_live_cell_changes_to_block_and_ckb_transaction.rb @@ -0,0 +1,6 @@ +class AddLiveCellChangesToBlockAndCkbTransaction < ActiveRecord::Migration[6.0] + def change + add_column :blocks, :live_cell_changes, :integer + add_column :ckb_transactions, :live_cell_changes, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 2592edadd..e8f94824b 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: 2019_12_16_080206) do +ActiveRecord::Schema.define(version: 2019_12_25_110229) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -89,6 +89,7 @@ t.decimal "length", precision: 30, default: "0" t.integer "uncles_count" t.decimal "compact_target", precision: 20 + t.integer "live_cell_changes" t.index ["block_hash"], name: "index_blocks_on_block_hash", unique: true t.index ["number"], name: "index_blocks_on_number" t.index ["timestamp"], name: "index_blocks_on_timestamp" @@ -147,6 +148,7 @@ t.jsonb "witnesses" t.binary "header_deps" t.jsonb "cell_deps" + t.integer "live_cell_changes" t.index ["block_id", "block_timestamp"], name: "index_ckb_transactions_on_block_id_and_block_timestamp" t.index ["is_cellbase"], name: "index_ckb_transactions_on_is_cellbase" t.index ["tx_hash", "block_id"], name: "index_ckb_transactions_on_tx_hash_and_block_id", unique: true From 9cbd02f59ae94d751ca2a4c9058134f0d6c723af Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:07:13 +0800 Subject: [PATCH 08/77] test: live cell changes on transaction --- test/models/ckb_sync/node_data_processor_test.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/models/ckb_sync/node_data_processor_test.rb b/test/models/ckb_sync/node_data_processor_test.rb index a9b474eb3..5e178d560 100644 --- a/test/models/ckb_sync/node_data_processor_test.rb +++ b/test/models/ckb_sync/node_data_processor_test.rb @@ -238,6 +238,22 @@ class NodeDataProcessorTest < ActiveSupport::TestCase end end + test "#process_block created ckb_transaction's live cell changes should equal to outputs count minus inputs count" do + VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do + node_block = fake_node_block("0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") + block = create(:block, :with_block_hash) + ckb_transaction1 = create(:ckb_transaction, tx_hash: "0x498315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block: block) + ckb_transaction2 = create(:ckb_transaction, tx_hash: "0x598315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block: block) + create(:cell_output, ckb_transaction: ckb_transaction1, cell_index: 1, tx_hash: "0x498315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", generated_by: ckb_transaction2, block: block, capacity: 4 * 10**8) + create(:cell_output, ckb_transaction: ckb_transaction2, cell_index: 2, tx_hash: "0x598315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", generated_by: ckb_transaction1, block: block) + node_block_transactions = node_block.transactions + + local_block = node_data_processor.process_block(node_block) + expected_live_cell_changes = node_block_transactions.map { |transaction| transaction.outputs.count - transaction.inputs.count } + assert_equal expected_live_cell_changes, local_block.ckb_transactions.map(&:live_cell_changes) + end + end + test "#process_block should create cell_inputs" do VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do node_block = CkbSync::Api.instance.get_block_by_number(DEFAULT_NODE_BLOCK_NUMBER) From 0c5589f32c57a6261cf13f03c23b9614fb8461c6 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:07:45 +0800 Subject: [PATCH 09/77] feat: save live_cell_changes to ckb_transaction --- app/models/ckb_sync/node_data_processor.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/ckb_sync/node_data_processor.rb b/app/models/ckb_sync/node_data_processor.rb index b756c475a..8a13c4ec2 100644 --- a/app/models/ckb_sync/node_data_processor.rb +++ b/app/models/ckb_sync/node_data_processor.rb @@ -337,7 +337,8 @@ def build_ckb_transaction(local_block, transaction, transaction_index) block_timestamp: local_block.timestamp, transaction_fee: 0, witnesses: transaction.witnesses, - is_cellbase: transaction_index.zero? + is_cellbase: transaction_index.zero?, + live_cell_changes: transaction.outputs.count - transaction.inputs.count ) end From 60ca75362b33a29dcf8d9515fdcf8ea38ef6c4d3 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:12:43 +0800 Subject: [PATCH 10/77] test: live_cell_changes on block --- test/models/ckb_sync/node_data_processor_test.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/models/ckb_sync/node_data_processor_test.rb b/test/models/ckb_sync/node_data_processor_test.rb index 5e178d560..51d200904 100644 --- a/test/models/ckb_sync/node_data_processor_test.rb +++ b/test/models/ckb_sync/node_data_processor_test.rb @@ -254,6 +254,20 @@ class NodeDataProcessorTest < ActiveSupport::TestCase end end + test "#process_block created block's live cell changes should equal to sum of ckb_transaction's live cell changes" do + VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do + node_block = fake_node_block("0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") + block = create(:block, :with_block_hash) + ckb_transaction1 = create(:ckb_transaction, tx_hash: "0x498315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block: block) + ckb_transaction2 = create(:ckb_transaction, tx_hash: "0x598315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block: block) + create(:cell_output, ckb_transaction: ckb_transaction1, cell_index: 1, tx_hash: "0x498315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", generated_by: ckb_transaction2, block: block, capacity: 4 * 10**8) + create(:cell_output, ckb_transaction: ckb_transaction2, cell_index: 2, tx_hash: "0x598315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", generated_by: ckb_transaction1, block: block) + + local_block = node_data_processor.process_block(node_block) + assert_equal local_block.live_cell_changes, local_block.ckb_transactions.sum(&:live_cell_changes) + end + end + test "#process_block should create cell_inputs" do VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do node_block = CkbSync::Api.instance.get_block_by_number(DEFAULT_NODE_BLOCK_NUMBER) From 76f3efcc4d5274ce534bdacb874f43fc2279bcaa Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:12:58 +0800 Subject: [PATCH 11/77] feat: save live_cell_changes to block --- app/models/ckb_sync/node_data_processor.rb | 1 + app/serializers/block_list_serializer.rb | 3 +++ test/controllers/api/v1/blocks_controller_test.rb | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/ckb_sync/node_data_processor.rb b/app/models/ckb_sync/node_data_processor.rb index 8a13c4ec2..c8743b6ce 100644 --- a/app/models/ckb_sync/node_data_processor.rb +++ b/app/models/ckb_sync/node_data_processor.rb @@ -29,6 +29,7 @@ def process_block(node_block) ckb_transactions = build_ckb_transactions(local_block, node_block.transactions, outputs, new_dao_depositor_events) local_block.ckb_transactions_count = ckb_transactions.size + local_block.live_cell_changes = ckb_transactions.sum(&:live_cell_changes) CkbTransaction.import!(ckb_transactions, recursive: true, batch_size: 3500, validate: false) input_capacities = ckb_transactions.reject(&:is_cellbase).pluck(:id).to_h { |id| [id, []] } update_tx_fee_related_data(local_block, input_capacities) diff --git a/app/serializers/block_list_serializer.rb b/app/serializers/block_list_serializer.rb index 96c5b7171..322c21d04 100644 --- a/app/serializers/block_list_serializer.rb +++ b/app/serializers/block_list_serializer.rb @@ -15,4 +15,7 @@ class BlockListSerializer attribute :transactions_count do |object| object.ckb_transactions_count.to_s end + attribute :live_cell_changes do |object| + object.live_cell_changes.to_s + end end diff --git a/test/controllers/api/v1/blocks_controller_test.rb b/test/controllers/api/v1/blocks_controller_test.rb index c7f1d6fcc..1257abb79 100644 --- a/test/controllers/api/v1/blocks_controller_test.rb +++ b/test/controllers/api/v1/blocks_controller_test.rb @@ -72,7 +72,7 @@ class BlocksControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_blocks_url response_block = json["data"].first - assert_equal %w(number transactions_count reward miner_hash timestamp ).sort, response_block["attributes"].keys.sort + assert_equal %w(number transactions_count reward miner_hash timestamp live_cell_changes).sort, response_block["attributes"].keys.sort end test "should return error object when page param is invalid" do From 7bcd7a5f0492204982abd9ed7b42f00ff3545978 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:15:03 +0800 Subject: [PATCH 12/77] feat: add capacity_involved column to ckb transaction --- app/models/ckb_transaction.rb | 1 + db/schema.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/ckb_transaction.rb b/app/models/ckb_transaction.rb index e019f4d6e..9aa8d6cbd 100644 --- a/app/models/ckb_transaction.rb +++ b/app/models/ckb_transaction.rb @@ -132,6 +132,7 @@ def recover_dead_cell # header_deps :binary # cell_deps :jsonb # live_cell_changes :integer +# capacity_involved :decimal(30, ) # # Indexes # diff --git a/db/schema.rb b/db/schema.rb index e8f94824b..3a05c2c84 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: 2019_12_25_110229) do +ActiveRecord::Schema.define(version: 2019_12_25_131337) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -149,6 +149,7 @@ t.binary "header_deps" t.jsonb "cell_deps" t.integer "live_cell_changes" + t.decimal "capacity_involved", precision: 30 t.index ["block_id", "block_timestamp"], name: "index_ckb_transactions_on_block_id_and_block_timestamp" t.index ["is_cellbase"], name: "index_ckb_transactions_on_is_cellbase" t.index ["tx_hash", "block_id"], name: "index_ckb_transactions_on_tx_hash_and_block_id", unique: true From 8aeec5c44ed9838f70601f85549c614efa14960e Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:39:59 +0800 Subject: [PATCH 13/77] test: capacity involved should equal to sum of inputs capacity --- test/models/ckb_sync/node_data_processor_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/models/ckb_sync/node_data_processor_test.rb b/test/models/ckb_sync/node_data_processor_test.rb index 51d200904..24fb54ff7 100644 --- a/test/models/ckb_sync/node_data_processor_test.rb +++ b/test/models/ckb_sync/node_data_processor_test.rb @@ -254,6 +254,21 @@ class NodeDataProcessorTest < ActiveSupport::TestCase end end + test "#process_block created ckb_transaction's capacity_involved should equal to outputs count minus inputs count" do + VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do + node_block = fake_node_block("0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") + block = create(:block, :with_block_hash) + ckb_transaction1 = create(:ckb_transaction, tx_hash: "0x498315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block: block) + ckb_transaction2 = create(:ckb_transaction, tx_hash: "0x598315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", block: block) + create(:cell_output, ckb_transaction: ckb_transaction1, cell_index: 1, tx_hash: "0x498315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", generated_by: ckb_transaction2, block: block) + create(:cell_output, ckb_transaction: ckb_transaction2, cell_index: 2, tx_hash: "0x598315db9c7ba144cca74d2e9122ac9b3a3da1641b2975ae321d91ec34f1c0e3", generated_by: ckb_transaction1, block: block) + local_block = node_data_processor.process_block(node_block) + expected_capacity_involved = local_block.ckb_transactions.map(&:capacity_involved) + + assert_equal expected_capacity_involved, local_block.ckb_transactions.map { |transaction| transaction.inputs.sum(:capacity) } + end + end + test "#process_block created block's live cell changes should equal to sum of ckb_transaction's live cell changes" do VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do node_block = fake_node_block("0x3307186493c5da8b91917924253a5ffd35231151649d0c7e2941aa8801815063") From 61fc5baf7754f7c84cc9ccf6825bf1b99b8ebaa8 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:43:07 +0800 Subject: [PATCH 14/77] feat: save capacity involved to ckb_transaction --- app/models/ckb_sync/node_data_processor.rb | 3 ++- ...191225131337_add_capacity_involved_to_ckb_transactions.rb | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20191225131337_add_capacity_involved_to_ckb_transactions.rb diff --git a/app/models/ckb_sync/node_data_processor.rb b/app/models/ckb_sync/node_data_processor.rb index c8743b6ce..dba8f19cf 100644 --- a/app/models/ckb_sync/node_data_processor.rb +++ b/app/models/ckb_sync/node_data_processor.rb @@ -502,10 +502,11 @@ def calculate_tx_fee(local_block, ckb_transactions, input_capacities, outputs) txs = [] ckb_transactions.each do |ckb_transaction| update_transaction_fee(ckb_transaction, input_capacities[ckb_transaction.id].sum, output_capacities[ckb_transaction.id].sum) + ckb_transaction.capacity_involved = input_capacities[ckb_transaction.id].sum txs << ckb_transaction end - CkbTransaction.import!(txs, validate: false, on_duplicate_key_update: [:transaction_fee]) + CkbTransaction.import!(txs, validate: false, on_duplicate_key_update: [:transaction_fee, :capacity_involved]) local_block.total_transaction_fee = local_block.ckb_transactions.sum(:transaction_fee) local_block.save! rescue ActiveRecord::RecordInvalid diff --git a/db/migrate/20191225131337_add_capacity_involved_to_ckb_transactions.rb b/db/migrate/20191225131337_add_capacity_involved_to_ckb_transactions.rb new file mode 100644 index 000000000..7cca9dc36 --- /dev/null +++ b/db/migrate/20191225131337_add_capacity_involved_to_ckb_transactions.rb @@ -0,0 +1,5 @@ +class AddCapacityInvolvedToCkbTransactions < ActiveRecord::Migration[6.0] + def change + add_column :ckb_transactions, :capacity_involved, :decimal, precision: 30, scale: 0 + end +end From 7d12caa3c52707421dc28265aeb2f54c5132cca6 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:52:35 +0800 Subject: [PATCH 15/77] feat: use ckb transaction list serializer --- .../api/v1/ckb_transactions_controller.rb | 2 +- .../ckb_transaction_list_serializer.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 app/serializers/ckb_transaction_list_serializer.rb diff --git a/app/controllers/api/v1/ckb_transactions_controller.rb b/app/controllers/api/v1/ckb_transactions_controller.rb index 8e28c9028..d33c33d5f 100644 --- a/app/controllers/api/v1/ckb_transactions_controller.rb +++ b/app/controllers/api/v1/ckb_transactions_controller.rb @@ -5,7 +5,7 @@ class CkbTransactionsController < ApplicationController def index ckb_transactions = CkbTransaction.recent.limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) - render json: CkbTransactionSerializer.new(ckb_transactions) + render json: CkbTransactionListSerializer.new(ckb_transactions) end def show diff --git a/app/serializers/ckb_transaction_list_serializer.rb b/app/serializers/ckb_transaction_list_serializer.rb new file mode 100644 index 000000000..84d4174e1 --- /dev/null +++ b/app/serializers/ckb_transaction_list_serializer.rb @@ -0,0 +1,18 @@ +class CkbTransactionListSerializer + include FastJsonapi::ObjectSerializer + + attribute :transaction_hash, &:tx_hash + + attribute :block_number do |object| + object.block_number.to_s + end + attribute :block_timestamp do |object| + object.block_timestamp.to_s + end + attribute :capacity_involved do |object| + object.capacity_involved.to_s + end + attribute :live_cell_changes do |object| + object.live_cell_changes.to_s + end +end From 18fa0f35f741dcbdeebce85e17d56c3ee778ba46 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 21:52:46 +0800 Subject: [PATCH 16/77] chore: adjust tests --- .../api/v1/ckb_transactions_controller_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/controllers/api/v1/ckb_transactions_controller_test.rb b/test/controllers/api/v1/ckb_transactions_controller_test.rb index 2c0e7609a..e3605b69d 100644 --- a/test/controllers/api/v1/ckb_transactions_controller_test.rb +++ b/test/controllers/api/v1/ckb_transactions_controller_test.rb @@ -179,7 +179,7 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_ckb_transactions_url - assert_equal CkbTransactionSerializer.new(ckb_transactions).serialized_json, response.body + assert_equal CkbTransactionListSerializer.new(ckb_transactions).serialized_json, response.body end test "serialized objects should in reverse order of timestamp" do @@ -201,7 +201,7 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_ckb_transactions_url response_ckb_transaction = json["data"].first - assert_equal %w(block_number transaction_hash block_timestamp transaction_fee version display_inputs display_outputs is_cellbase income witnesses cell_deps header_deps).sort, response_ckb_transaction["attributes"].keys.sort + assert_equal %w(block_number transaction_hash block_timestamp capacity_involved live_cell_changes).sort, response_ckb_transaction["attributes"].keys.sort end test "should return the corresponding number of ckb transactions " do @@ -211,7 +211,7 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_ckb_transactions_url ckb_transactions = CkbTransaction.order(block_timestamp: :desc).limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) - response_ckb_transaction = CkbTransactionSerializer.new(ckb_transactions).serialized_json + response_ckb_transaction = CkbTransactionListSerializer.new(ckb_transactions).serialized_json assert_equal response_ckb_transaction, response.body assert_equal 15, json["data"].size end @@ -221,7 +221,7 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest valid_get api_v1_ckb_transactions_url - response_ckb_transaction = CkbTransactionSerializer.new(ckb_transactions).serialized_json + response_ckb_transaction = CkbTransactionListSerializer.new(ckb_transactions).serialized_json assert_equal [], json["data"] assert_equal response_ckb_transaction, response.body From 7c8dbedaec3dc44b90eba82a39d14bfcbfd0db0b Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 22:09:29 +0800 Subject: [PATCH 17/77] test: ckb transactions index page params --- .../v1/ckb_transactions_controller_test.rb | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/controllers/api/v1/ckb_transactions_controller_test.rb b/test/controllers/api/v1/ckb_transactions_controller_test.rb index e3605b69d..a459ca627 100644 --- a/test/controllers/api/v1/ckb_transactions_controller_test.rb +++ b/test/controllers/api/v1/ckb_transactions_controller_test.rb @@ -226,6 +226,41 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest assert_equal [], json["data"] assert_equal response_ckb_transaction, response.body end + + test "should return error object when page param is invalid" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 15, block: block) + error_object = Api::V1::Exceptions::PageParamError.new + response_json = RequestErrorSerializer.new([error_object], message: error_object.title).serialized_json + + valid_get api_v1_ckb_transactions_url, params: { page: "aaa" } + + assert_equal response_json, response.body + end + + test "should return error object when page size param is invalid" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 15, block: block) + error_object = Api::V1::Exceptions::PageSizeParamError.new + response_json = RequestErrorSerializer.new([error_object], message: error_object.title).serialized_json + + valid_get api_v1_ckb_transactions_url, params: { page_size: "aaa" } + + assert_equal response_json, response.body + end + + test "should return error object when page and page size param are invalid" do + errors = [] + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 15, block: block) + errors << Api::V1::Exceptions::PageParamError.new + errors << Api::V1::Exceptions::PageSizeParamError.new + response_json = RequestErrorSerializer.new(errors, message: errors.first.title).serialized_json + + valid_get api_v1_ckb_transactions_url, params: { page: "bbb", page_size: "aaa" } + + assert_equal response_json, response.body + end end end end From 2b4fa1a464b87d6fe69710861173885810760f7d Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 22:25:46 +0800 Subject: [PATCH 18/77] test: ckb transactions index pagination --- .../v1/ckb_transactions_controller_test.rb | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/controllers/api/v1/ckb_transactions_controller_test.rb b/test/controllers/api/v1/ckb_transactions_controller_test.rb index a459ca627..0315258d0 100644 --- a/test/controllers/api/v1/ckb_transactions_controller_test.rb +++ b/test/controllers/api/v1/ckb_transactions_controller_test.rb @@ -261,6 +261,55 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest assert_equal response_json, response.body end + + test "should return 15 records when page and page_size are not set" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 20, block: block) + + valid_get api_v1_ckb_transactions_url + + assert_equal 15, json["data"].size + end + + test "should return corresponding page's records when page is set and page_size is not set" do + page = 2 + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 20, block: block) + ckb_transactions = CkbTransaction.order(block_timestamp: :desc).limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) + + valid_get api_v1_ckb_transactions_url, params: { page: page } + + response_ckb_transactions = CkbTransactionListSerializer.new(ckb_transactions, {}).serialized_json + + assert_equal response_ckb_transactions, response.body + assert_equal 15, json["data"].size + end + + test "should return the corresponding number of ckb_transactions when page is not set and page_size is set" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 20, block: block) + + valid_get api_v1_ckb_transactions_url, params: { page_size: 12 } + + ckb_transactions = CkbTransaction.order(block_timestamp: :desc).limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) + response_ckb_transactions = CkbTransactionListSerializer.new(ckb_transactions, {}).serialized_json + assert_equal response_ckb_transactions, response.body + assert_equal 15, json["data"].size + end + + test "should return the corresponding blocks when page and page_size are set" do + block = create(:block, :with_block_hash) + create_list(:ckb_transaction, 15, block: block) + page = 2 + page_size = 5 + ckb_transactions = CkbTransaction.order(block_timestamp: :desc).page(page).per(page_size) + + valid_get api_v1_ckb_transactions_url, params: { page: page, page_size: page_size } + + options = FastJsonapi::PaginationMetaGenerator.new(request: request, records: ckb_transactions, page: page, page_size: page_size).call + response_ckb_transactions = CkbTransactionListSerializer.new(ckb_transactions, options).serialized_json + assert_equal response_ckb_transactions, response.body + end end end end From 2251ba25b83a404c038a11c7672d1de3ccef8d0a Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 22:26:10 +0800 Subject: [PATCH 19/77] feat: add pagination to ckb transactions controller --- .../api/v1/ckb_transactions_controller.rb | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/ckb_transactions_controller.rb b/app/controllers/api/v1/ckb_transactions_controller.rb index d33c33d5f..531e29616 100644 --- a/app/controllers/api/v1/ckb_transactions_controller.rb +++ b/app/controllers/api/v1/ckb_transactions_controller.rb @@ -2,10 +2,18 @@ module Api module V1 class CkbTransactionsController < ApplicationController before_action :validate_query_params, only: :show + before_action :validate_pagination_params, :pagination_params, only: :index def index - ckb_transactions = CkbTransaction.recent.limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) - render json: CkbTransactionListSerializer.new(ckb_transactions) + if from_home_page? + ckb_transactions = CkbTransaction.recent.limit(ENV["HOMEPAGE_TRANSACTIONS_RECORDS_COUNT"].to_i) + options = {} + else + ckb_transactions = CkbTransaction.recent.page(@page).per(@page_size) + options = FastJsonapi::PaginationMetaGenerator.new(request: request, records: ckb_transactions, page: @page, page_size: @page_size).call + end + + render json: CkbTransactionListSerializer.new(ckb_transactions, options) end def show @@ -18,6 +26,15 @@ def show private + def from_home_page? + params[:page].blank? || params[:page_size].blank? + end + + def pagination_params + @page = params[:page] || 1 + @page_size = params[:page_size] || CkbTransaction.default_per_page + end + def validate_query_params validator = Validations::CkbTransaction.new(params) From d4a5887c7f77f3c9740ac8b129fee731c3410191 Mon Sep 17 00:00:00 2001 From: shaojunda Date: Wed, 25 Dec 2019 22:44:28 +0800 Subject: [PATCH 20/77] chore: update api doc --- doc/api.raml | 94 +++++++++++++++++++++++++++++++++++++++++++++ public/api_doc.html | 2 +- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/doc/api.raml b/doc/api.raml index aef3558b2..60610d770 100644 --- a/doc/api.raml +++ b/doc/api.raml @@ -596,6 +596,27 @@ types: } } + ckb_transaction_list_attributes: { + type: "object", + properties: { + "transaction_hash": { + type: "string" + }, + "block_number": { + type: "string" + }, + "block_timestamp": { + type: "string" + }, + "capacity_involved": { + type: "string" + }, + "live_cell_changes": { + type: "string" + } + } + } + index_statistic_info: { type: object, properties: { @@ -662,6 +683,15 @@ types: } } + ckb_transaction_list_response: { + type: object, + properties: { + "data": { + "type": "ckb_transaction_list_attributes" + } + } + } + blocks_response: { type: object, properties: { @@ -1039,6 +1069,70 @@ types: } /transactions: + get: + description: Returns blocks in reverse chronological order. + queryParameters: + page_size: + type: integer + default: 10 + page: + type: integer + default: 1 + responses: + 200: + body: + application/vnd.api+json: + type: ckb_transaction_list_response + example: | + { + "data": [ + { + "id": "519759", + "type": "ckb_transaction_list", + "attributes": { + "transaction_hash": "0x51c4008aecf7b32762f8de7b1e0db97b0b99af6dfbedacddca4723e4e3469735", + "block_number": "355801", + "block_timestamp": "1577284662673", + "capacity_involved": "", + "live_cell_changes": "0" + } + }, + { + "id": "519760", + "type": "ckb_transaction_list", + "attributes": { + "transaction_hash": "0x93dcd049c02c94a4f8b83ed86e6dfdd662bb381585f6294e5cc316f301ed688d", + "block_number": "355801", + "block_timestamp": "1577284662673", + "capacity_involved": "", + "live_cell_changes": "0" + } + }, + { + "id": "519757", + "type": "ckb_transaction_list", + "attributes": { + "transaction_hash": "0xfe642e494030e77c46753f7ac2d29c38d6780e38c1a3a7accb6b4adf415a511b", + "block_number": "355800", + "block_timestamp": "1577284656255", + "capacity_involved": "", + "live_cell_changes": "0" + } + }, + ] + "meta": { + "total": 100, + "page_size": 15, + }, + links: { + "self": "https://explorer.nervos.org/api/v1/transactions?page_size=15", + "first": "https://explorer.nervos.org/api/v1/transactions?page=1&page_size=10", + "prev": "https://explorer.nervos.org/api/v1/transactions?page=2&page_size=10", + "next": "https://explorer.nervos.org/api/v1/transactions?page=2&page_size=15", + "last": "https://explorer.nervos.org/api/v1/transactions?page=28909&page_size=15" + } + } + /{tx_hash}: uriParameters: tx_hash: diff --git a/public/api_doc.html b/public/api_doc.html index cc2c3f507..e71610e37 100644 --- a/public/api_doc.html +++ b/public/api_doc.html @@ -323,7 +323,7 @@ } ] } -

/transactions

get

Returns a transaction by transaction hash

/transactions

get

Returns blocks in reverse chronological order.

get

Returns a transaction by transaction hash

/transactions

get

Returns blocks in reverse chronological order.

get

Returns a transaction by transaction hash

/transactions

get

Returns blocks in reverse chronological order.

get

Returns a transaction by transaction hash

/contracts

get

Returns a contract by contract name

/contracts

get

Returns a contract by contract name