Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support query tx in tx pool #739

Merged
merged 16 commits into from
Nov 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/api/v1/ckb_transactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def index
end

def show
ckb_transaction = CkbTransaction.cached_find(params[:id])
ckb_transaction = CkbTransaction.cached_find(params[:id]) || PoolTransactionEntry.find_by(tx_hash: params[:id])

raise Api::V1::Exceptions::CkbTransactionNotFoundError if ckb_transaction.blank?

Expand Down
5 changes: 5 additions & 0 deletions app/models/ckb_sync/node_data_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def process_block(node_block)
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)
update_pool_tx_status(ckb_transactions)
input_capacities = ckb_transactions.reject(&:is_cellbase).pluck(:id).to_h { |id| [id, []] }
update_tx_fee_related_data(local_block, input_capacities, udt_infos)
calculate_tx_fee(local_block, ckb_transactions, input_capacities, outputs.group_by(&:ckb_transaction_id))
Expand All @@ -53,6 +54,10 @@ def process_block(node_block)

private

def update_pool_tx_status(ckb_transactions)
PoolTransactionEntry.pool_transaction_pending.where(tx_hash: ckb_transactions.pluck(:tx_hash)).update_all(tx_status: "committed")
end

def increase_records_count(ckb_transactions)
block_counter = TableRecordCount.find_by(table_name: "blocks")
block_counter.increment!(:count)
Expand Down
10 changes: 10 additions & 0 deletions app/models/ckb_transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ class CkbTransaction < ApplicationRecord
paginates_per 10
max_paginates_per MAX_PAGINATES_PER

enum tx_status: { pending: 0, proposed: 1, committed: 2 }, _prefix: :ckb_transaction

belongs_to :block
has_many :account_books, dependent: :destroy
has_many :addresses, through: :account_books
Expand Down Expand Up @@ -62,6 +64,14 @@ def dao_transaction?
inputs.where(cell_type: %w(nervos_dao_deposit nervos_dao_withdrawing)).exists? || outputs.where(cell_type: %w(nervos_dao_deposit nervos_dao_withdrawing)).exists?
end

def tx_status
"committed"
end

def cell_info
nil
end

private

def normal_tx_display_outputs(previews)
Expand Down
52 changes: 52 additions & 0 deletions app/models/pool_transaction_entry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class PoolTransactionEntry < ApplicationRecord
enum tx_status: { pending: 0, proposed: 1, committed: 2 }, _prefix: :pool_transaction

def is_cellbase
false
end

def income(address = nil)
nil
end

def display_outputs(previews: false)
self.attributes["display_outputs"]
end

def display_inputs(previews: false)
self.attributes["display_inputs"]
end

def proposal_short_id
tx_hash[0...12]
end
end

# == Schema Information
#
# Table name: pool_transaction_entries
#
# id :bigint not null, primary key
# cell_deps :jsonb
# tx_hash :binary
# header_deps :jsonb
# inputs :jsonb
# outputs :jsonb
# outputs_data :jsonb
# version :integer
# witnesses :jsonb
# transaction_fee :decimal(30, )
# block_number :decimal(30, )
# block_timestamp :decimal(30, )
# cycles :decimal(30, )
# tx_size :decimal(30, )
# display_inputs :jsonb
# display_outputs :jsonb
# tx_status :integer default("pending")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_pool_transaction_entries_on_tx_hash (tx_hash) UNIQUE
#
7 changes: 6 additions & 1 deletion app/models/suggest_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ def find_udt_by_type_hash
UdtSerializer.new(udt) if udt.present?
end

def find_pool_tx_by_hash
tx = PoolTransactionEntry.find_by(tx_hash: query_key)
CkbTransactionSerializer.new(tx) if tx.present?
end

def find_by_hex
Block.cached_find(query_key) || find_ckb_transaction_by_hash || find_address_by_lock_hash || find_udt_by_type_hash
Block.cached_find(query_key) || find_ckb_transaction_by_hash || find_pool_tx_by_hash || find_address_by_lock_hash || find_udt_by_type_hash
end
end
2 changes: 1 addition & 1 deletion app/serializers/ckb_transaction_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class CkbTransactionSerializer
include FastJsonapi::ObjectSerializer

attributes :is_cellbase, :witnesses, :cell_deps, :header_deps
attributes :is_cellbase, :witnesses, :cell_deps, :header_deps, :tx_status

attribute :transaction_hash, &:tx_hash

Expand Down
26 changes: 26 additions & 0 deletions db/migrate/20201029140549_create_pool_transaction_entries.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class CreatePoolTransactionEntries < ActiveRecord::Migration[6.0]
def change
create_table :pool_transaction_entries do |t|
t.jsonb :cell_deps
t.binary :tx_hash
t.jsonb :header_deps
t.jsonb :inputs
t.jsonb :outputs
t.jsonb :outputs_data
t.integer :version
t.jsonb :witnesses
t.decimal :transaction_fee, precision: 30, scale: 0
t.decimal :block_number, precision: 30, scale: 0
t.decimal :block_timestamp, precision: 30, scale: 0
t.decimal :cycles, precision: 30, scale: 0
t.decimal :tx_size, precision: 30, scale: 0
t.jsonb :display_inputs
t.jsonb :display_outputs
t.integer :tx_status, default: 0

t.timestamps
end

add_index :pool_transaction_entries, :tx_hash, unique: true
end
end
24 changes: 23 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2020_08_06_081043) do
ActiveRecord::Schema.define(version: 2020_10_29_140549) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -355,6 +355,28 @@
t.index ["block_number"], name: "index_mining_infos_on_block_number"
end

create_table "pool_transaction_entries", force: :cascade do |t|
t.jsonb "cell_deps"
t.binary "tx_hash"
t.jsonb "header_deps"
t.jsonb "inputs"
t.jsonb "outputs"
t.jsonb "outputs_data"
t.integer "version"
t.jsonb "witnesses"
t.decimal "transaction_fee", precision: 30
t.decimal "block_number", precision: 30
t.decimal "block_timestamp", precision: 30
t.decimal "cycles", precision: 30
t.decimal "tx_size", precision: 30
t.jsonb "display_inputs"
t.jsonb "display_outputs"
t.integer "tx_status", default: 0
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["tx_hash"], name: "index_pool_transaction_entries_on_tx_hash", unique: true
end

create_table "table_record_counts", force: :cascade do |t|
t.string "table_name"
t.bigint "count"
Expand Down
13 changes: 11 additions & 2 deletions test/controllers/api/v1/ckb_transactions_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest
assert_equal CkbTransactionSerializer.new(ckb_transaction).serialized_json, response.body
end

test "should return pool tx when tx is in the pool" do
tx = create(:pool_transaction_entry)

valid_get api_v1_ckb_transaction_url(tx.tx_hash)

expected_response = CkbTransactionSerializer.new(tx).serialized_json
assert_equal expected_response, response.body
end

test "should contain right keys in the serialized object when call show" do
create(:table_record_count, :block_counter)
create(:table_record_count, :ckb_transactions_counter)
Expand All @@ -99,7 +108,7 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest
valid_get api_v1_ckb_transaction_url(ckb_transaction.tx_hash)

response_tx_transaction = json["data"]
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_tx_transaction["attributes"].keys.sort
assert_equal %w(block_number transaction_hash block_timestamp transaction_fee version display_inputs display_outputs is_cellbase income witnesses cell_deps header_deps tx_status).sort, response_tx_transaction["attributes"].keys.sort
end

test "returned income should be null" do
Expand Down Expand Up @@ -303,7 +312,7 @@ class CkbTransactionsControllerTest < ActionDispatch::IntegrationTest
assert_equal 15, json["data"].size
end

test "should return the corresponding blocks when page and page_size are set" do
test "should return the corresponding transactions when page and page_size are set" do
block = create(:block, :with_block_hash)
create_list(:ckb_transaction, 15, block: block)
create(:table_record_count, :block_counter, count: Block.count)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class DaoContractTransactionsControllerTest < ActionDispatch::IntegrationTest
valid_get api_v1_dao_contract_transaction_url(ckb_transaction.tx_hash)

response_tx_transaction = json["data"]
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_tx_transaction["attributes"].keys.sort
assert_equal %w(block_number transaction_hash block_timestamp transaction_fee version display_inputs display_outputs is_cellbase income witnesses cell_deps header_deps tx_status).sort, response_tx_transaction["attributes"].keys.sort
end

test "should return error object when given tx hash corresponds to a normal transaction" do
Expand Down
5 changes: 5 additions & 0 deletions test/factories/pool_transaction_entry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FactoryBot.define do
factory :pool_transaction_entry do
tx_hash { "0x#{SecureRandom.hex(32)}" }
end
end
39 changes: 39 additions & 0 deletions test/models/ckb_sync/node_data_processor_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,45 @@ class NodeDataProcessorTest < ActiveSupport::TestCase
end
end

test "#process_block should change pool transaction's status to committed when it has been committed to current block" do
CkbSync::Api.any_instance.stubs(:get_epoch_by_number).returns(
CKB::Types::Epoch.new(
compact_target: "0x1000",
length: "0x07d0",
number: "0x0",
start_number: "0x0"
)
)
VCR.use_cassette("blocks/11") do
tx = create(:pool_transaction_entry)
node_block = CkbSync::Api.instance.get_block_by_number(11)
create(:block, :with_block_hash, number: node_block.header.number - 1)
node_block.transactions.first.hash = tx.tx_hash
assert_changes -> { tx.reload.tx_status }, from: "pending", to: "committed" do
node_data_processor.process_block(node_block)
end
end
end

test "#process_block should not change pool transaction's status to committed when it has not been committed to current block" do
CkbSync::Api.any_instance.stubs(:get_epoch_by_number).returns(
CKB::Types::Epoch.new(
compact_target: "0x1000",
length: "0x07d0",
number: "0x0",
start_number: "0x0"
)
)
VCR.use_cassette("blocks/11") do
tx = create(:pool_transaction_entry)
node_block = CkbSync::Api.instance.get_block_by_number(11)
create(:block, :with_block_hash, number: node_block.header.number - 1)
assert_no_changes -> { tx.reload.tx_status } do
node_data_processor.process_block(node_block)
end
end
end

test "#process_block should generate miner's lock when cellbase has witnesses" do
CkbSync::Api.any_instance.stubs(:get_epoch_by_number).returns(
CKB::Types::Epoch.new(
Expand Down
13 changes: 13 additions & 0 deletions test/models/pool_transaction_entry_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require "test_helper"

class PoolTransactionEntryTest < ActiveSupport::TestCase
test "is_cellbase should always be false" do
tx = create(:pool_transaction_entry)
assert_equal false, tx.is_cellbase
end

test "income should always be nil" do
tx = create(:pool_transaction_entry)
assert_nil tx.income
end
end
6 changes: 6 additions & 0 deletions test/models/suggest_query_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,10 @@ class SuggestQueryTest < ActiveSupport::TestCase
SuggestQuery.new(udt.type_hash).find!
end
end

test "should return pool tx when tx is in the pool" do
tx = create(:pool_transaction_entry)
expected_response = CkbTransactionSerializer.new(tx).serialized_json
assert_equal expected_response, SuggestQuery.new(tx.tx_hash).find!.serialized_json
end
end