diff --git a/.rubocop.yml b/.rubocop.yml index 94304388b..87fa66de2 100755 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -449,9 +449,9 @@ Layout/InitialIndentation: Enabled: false Layout/LineLength: - Description: 'Limit lines to 80 characters.' + Description: 'Limit lines to 200 characters.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#80-character-limits' - Max: 80 + Max: 200 # Lint diff --git a/Gemfile b/Gemfile index b03462596..ff1ef8e1d 100644 --- a/Gemfile +++ b/Gemfile @@ -66,7 +66,6 @@ gem "with_advisory_lock" gem "nokogiri", ">= 1.11.0.rc4" -gem "benchmark_methods", require: false gem "sentry-ruby" gem "sentry-rails" gem "sentry-sidekiq" diff --git a/Gemfile.lock b/Gemfile.lock index 2f9df335a..a865302b5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,7 +111,6 @@ GEM awesome_print (1.9.2) backport (1.2.0) benchmark (0.2.1) - benchmark_methods (0.7) bigdecimal (3.1.4) bootsnap (1.13.0) msgpack (~> 1.2) @@ -479,7 +478,6 @@ DEPENDENCIES annotate async-websocket (~> 0.22.1) awesome_print - benchmark_methods bigdecimal bootsnap ckb-sdk-ruby! diff --git a/app/controllers/api/v1/omiga_inscriptions_controller.rb b/app/controllers/api/v1/omiga_inscriptions_controller.rb index 806222116..44f1e95ec 100644 --- a/app/controllers/api/v1/omiga_inscriptions_controller.rb +++ b/app/controllers/api/v1/omiga_inscriptions_controller.rb @@ -6,7 +6,15 @@ class OmigaInscriptionsController < ApplicationController only: :index def index - udts = Udt.omiga_inscription + pre_udt_hashes = OmigaInscriptionInfo.where.not(pre_udt_hash: nil).pluck(:pre_udt_hash) + udts = + if pre_udt_hashes.present? + Udt.joins(:omiga_inscription_info).where.not( + "omiga_inscription_infos.mint_status = 1 and omiga_inscription_infos.udt_hash IN (?)", pre_udt_hashes + ) + else + Udt.omiga_inscription + end if stale?(udts) udts = sort_udts(udts).page(@page).per(@page_size).fast_page @@ -22,15 +30,27 @@ def index end def show - udt = Udt.find_by!(type_hash: params[:id]) - render json: UdtSerializer.new(udt) - rescue ActiveRecord::RecordNotFound - raise Api::V1::Exceptions::UdtNotFoundError + udt = + if params[:status] == "closed" + Udt.joins(:omiga_inscription_info).where( + "omiga_inscription_infos.type_hash = ? and omiga_inscription_infos.mint_status = 1", params[:id] + ).first + else + Udt.joins(:omiga_inscription_info).where( + "udts.type_hash = ? or omiga_inscription_infos.type_hash = ?", params[:id], params[:id] + ).order("id DESC").first + end + + if udt.nil? + raise Api::V1::Exceptions::UdtNotFoundError + else + render json: UdtSerializer.new(udt) + end end def download_csv args = params.permit(:id, :start_date, :end_date, :start_number, - :end_number, udt: {}) + :end_number, :status, udt: {}) file = CsvExportable::ExportOmigaInscriptionTransactionsJob.perform_now(args.to_h) send_data file, type: "text/csv; charset=utf-8; header=present", diff --git a/app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb b/app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb index 84924ed73..343b1f003 100644 --- a/app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb +++ b/app/jobs/csv_exportable/export_omiga_inscription_transactions_job.rb @@ -1,7 +1,16 @@ module CsvExportable class ExportOmigaInscriptionTransactionsJob < BaseExporter def perform(args) - udt = Udt.find_by!(type_hash: args[:id], published: true) + udt = + if args[:status] == "closed" + Udt.joins(:omiga_inscription_info).where( + "omiga_inscription_infos.type_hash = ? and omiga_inscription_infos.mint_status = 1", args[:id] + ).first + else + Udt.joins(:omiga_inscription_info).where( + "udts.type_hash = ? or omiga_inscription_infos.type_hash = ?", args[:id], args[:id] + ).order("id DESC").first + end ckb_transactions = udt.ckb_transactions if args[:start_date].present? diff --git a/app/models/ckb_sync/new_node_data_processor.rb b/app/models/ckb_sync/new_node_data_processor.rb index 17d5a0013..8eb7ef38b 100644 --- a/app/models/ckb_sync/new_node_data_processor.rb +++ b/app/models/ckb_sync/new_node_data_processor.rb @@ -1,4 +1,3 @@ -require "benchmark_methods" require "newrelic_rpm" require "new_relic/agent/method_tracer" @@ -6,25 +5,18 @@ module CkbSync class NewNodeDataProcessor include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation include NewRelic::Agent::MethodTracer - # include BenchmarkMethods include Redis::Objects + value :reorg_started_at, global: true - attr_accessor :enable_cota - # benchmark :call, :process_block, :build_block!, :build_uncle_blocks!, :build_ckb_transactions!, :build_udts!, :process_ckb_txs, :build_cells_and_locks!, - # :update_ckb_txs_rel_and_fee, :update_block_info!, :update_block_reward_info!, :update_mining_info, :update_table_records_count, - # :update_or_create_udt_accounts!, :update_udt_info, :process_dao_events!, :update_addresses_info, - # :cache_address_txs, :flush_inputs_outputs_caches, :generate_statistics_data attr_accessor :local_tip_block, :pending_raw_block, :ckb_txs, :target_block, :addrs_changes, - :outputs, :inputs, :outputs_data, - :udt_address_ids, :contained_address_ids, :dao_address_ids, :contained_udt_ids, - :tx_cell_deps, :cell_datas, :cell_data_hashes + :outputs, :inputs, :outputs_data, :udt_address_ids, :contained_address_ids, + :dao_address_ids, :contained_udt_ids, :cell_datas, :enable_cota def initialize(enable_cota = ENV["COTA_AGGREGATOR_URL"].present?) @enable_cota = enable_cota @local_cache = LocalCache.new @offset = ENV["BLOCK_OFFSET"].to_i @cell_datas = {} # data_hash => data - @cell_data_hashes = {} # cell_id => data_hash end # returns the remaining block numbers to process @@ -67,7 +59,6 @@ def process_block(node_block, refresh_balance: true) inputs = @inputs = {} outputs = @outputs = {} outputs_data = @outputs_data = {} - @tx_cell_deps = {} @ckb_txs = build_ckb_transactions!(node_block, local_block, inputs, outputs, outputs_data).to_a benchmark :build_udts!, local_block, outputs, outputs_data @@ -96,18 +87,15 @@ def process_block(node_block, refresh_balance: true) # maybe can be changed to asynchronous update benchmark :update_udt_info, local_block benchmark :process_dao_events!, local_block - if refresh_balance - benchmark :update_addresses_info, addrs_changes, local_block - end + benchmark :update_addresses_info, addrs_changes, local_block, refresh_balance end - benchmark :flush_inputs_outputs_caches, local_block - benchmark :generate_statistics_data, local_block - # benchmark :generate_deployed_cells_and_referring_cells, local_block + flush_inputs_outputs_caches(local_block) + generate_statistics_data(local_block) + generate_deployed_cells_and_referring_cells(local_block) + detect_cota_infos(local_block) - FetchCotaWorker.perform_async(local_block.number) if enable_cota local_block.update_counter_for_ckb_node_version - local_block end @@ -132,17 +120,17 @@ def check_invalid_address(address) private def generate_deployed_cells_and_referring_cells(local_block) - local_block.ckb_transactions.each do |ckb_transaction| - DeployedCell.create_initial_data_for_ckb_transaction ckb_transaction, - tx_cell_deps[ckb_transaction.tx_hash] - ReferringCell.create_initial_data_for_ckb_transaction ckb_transaction - end + GenerateCellDependenciesWorker.perform_async(local_block.id) end def generate_statistics_data(local_block) GenerateStatisticsDataWorker.perform_async(local_block.id) end + def detect_cota_infos(local_block) + FetchCotaWorker.perform_async(local_block.number) if enable_cota + end + def process_ckb_txs( node_block, ckb_txs, contained_address_ids, contained_udt_ids, dao_address_ids, tags, udt_address_ids @@ -183,11 +171,9 @@ def process_dao_events!(local_tip_block = @local_tip_block) new_dao_depositors = {} dao_contract = DaoContract.default_contract process_deposit_dao_events!(local_block, new_dao_depositors, dao_contract) - process_withdraw_dao_events!(local_block, new_dao_depositors, - dao_contract) + process_withdraw_dao_events!(local_block, new_dao_depositors, dao_contract) process_interest_dao_events!(local_block, dao_contract) - build_new_dao_depositor_events!(local_block, new_dao_depositors, - dao_contract) + build_new_dao_depositor_events!(local_block, new_dao_depositors, dao_contract) # update dao contract ckb_transactions_count dao_contract.increment!(:ckb_transactions_count, @@ -196,21 +182,21 @@ def process_dao_events!(local_tip_block = @local_tip_block) ).count) end - def build_new_dao_depositor_events!(local_block, new_dao_depositors, -dao_contract) + def build_new_dao_depositor_events!(local_block, new_dao_depositors, dao_contract) new_dao_events_attributes = [] new_dao_depositors.each do |address_id, ckb_transaction_id| new_dao_events_attributes << { block_id: local_block.id, ckb_transaction_id:, address_id:, event_type: "new_dao_depositor", - value: 1, status: "processed", contract_id: dao_contract.id, block_timestamp: local_block.timestamp, created_at: Time.current, - updated_at: Time.current + value: 1, status: "processed", contract_id: dao_contract.id, block_timestamp: local_block.timestamp, + created_at: Time.current, updated_at: Time.current } end if new_dao_events_attributes.present? DaoEvent.insert_all!(new_dao_events_attributes) dao_contract.update!( - total_depositors_count: dao_contract.total_depositors_count + new_dao_events_attributes.size, depositors_count: dao_contract.depositors_count + new_dao_events_attributes.size, + total_depositors_count: dao_contract.total_depositors_count + new_dao_events_attributes.size, + depositors_count: dao_contract.depositors_count + new_dao_events_attributes.size, ) address_ids = [] new_dao_events_attributes.each do |dao_event_attr| @@ -253,8 +239,7 @@ def process_withdraw_dao_events!(local_block, _new_dao_depositors, } end if addrs_withdraw_info[address.id][:dao_deposit] < 0 - addrs_withdraw_info[address.id][:dao_deposit] = - 0 + addrs_withdraw_info[address.id][:dao_deposit] = 0 end dao_events_attributes << { ckb_transaction_id: dao_input.ckb_transaction_id, @@ -339,7 +324,6 @@ def process_interest_dao_events!(local_block, dao_contract) created_at: Time.current, updated_at: Time.current, } - address_dao_deposit = Address.where(id: previous_cell_output.address_id).pick(:dao_deposit) claimed_compensation += interest end DaoEvent.insert_all!(dao_events_attributes) if dao_events_attributes.present? @@ -351,8 +335,7 @@ def process_interest_dao_events!(local_block, dao_contract) update_addresses_dao_info(addrs_withdraw_info) end - def process_deposit_dao_events!(local_block, new_dao_depositors, -dao_contract) + def process_deposit_dao_events!(local_block, new_dao_depositors, dao_contract) deposit_amount = 0 deposit_transaction_ids = Set.new addresses_deposit_info = {} @@ -421,13 +404,11 @@ def update_udt_info(local_block) local_block.cell_outputs.udt.select(:id, :type_hash).each do |udt_output| type_hashes << udt_output.type_hash end - local_block.cell_outputs.omiga_inscription.select(:id, - :type_hash).each do |udt_output| + local_block.cell_outputs.omiga_inscription.select(:id, :type_hash).each do |udt_output| type_hashes << udt_output.type_hash end local_block.ckb_transactions.pluck(:id).each do |tx_id| - CellOutput.where(consumed_by_id: tx_id).udt.select(:id, - :type_hash).each do |udt_output| + CellOutput.where(consumed_by_id: tx_id).udt.select(:id, :type_hash).each do |udt_output| type_hashes << udt_output.type_hash end end @@ -580,34 +561,8 @@ def update_mining_info(local_block) CkbUtils.update_current_block_mining_info(local_block) end - def update_addresses_info(addrs_change, local_block) - ### Backup the old upsert code - # addrs = [] - # attributes = - # addrs_change.map do |addr_id, values| - # addr = Address.where(id: addr_id).select(:id, :address_hash, :lock_hash, :balance, :ckb_transactions_count, :dao_transactions_count, :live_cells_count, :created_at, :balance_occupied).take! - # balance_diff = values[:balance_diff] - # balance_occupied_diff = values[:balance_occupied_diff].presence || 0 - # live_cells_diff = values[:cells_diff] - # dao_txs_count = values[:dao_txs].present? ? values[:dao_txs].size : 0 - # ckb_txs_count = values[:ckb_txs].present? ? values[:ckb_txs].size : 0 - # addrs << addr - # { - # id: addr.id, - # balance: addr.balance + balance_diff, - # balance_occupied: addr.balance_occupied + balance_occupied_diff, - # ckb_transactions_count: addr.ckb_transactions_count + ckb_txs_count, - # live_cells_count: addr.live_cells_count + live_cells_diff, - # dao_transactions_count: addr.dao_transactions_count + dao_txs_count, - # created_at: addr.created_at, - # updated_at: Time.current - # } - # end - # if attributes.present? - # Address.upsert_all(attributes) - # addrs.each(&:touch) - # end - + def update_addresses_info(addrs_change, local_block, refresh_balance) + return unless refresh_balance ### because `upsert` don't validate record, so it may pass invalid data into database. ### here we use one by one update (maybe slower) addrs_change.each do |addr_id, values| @@ -649,26 +604,49 @@ def save_address_block_snapshot!(addr, local_block) end def update_block_info!(local_block) - local_block.update!(total_transaction_fee: local_block.ckb_transactions.sum(:transaction_fee), - ckb_transactions_count: local_block.ckb_transactions.count, - live_cell_changes: local_block.ckb_transactions.sum(&:live_cell_changes), - address_ids: local_block.ckb_transactions.map(&:contained_address_ids).flatten.uniq) + local_block.update!( + total_transaction_fee: local_block.ckb_transactions.sum(:transaction_fee), + ckb_transactions_count: local_block.ckb_transactions.count, + live_cell_changes: local_block.ckb_transactions.sum(&:live_cell_changes), + address_ids: local_block.ckb_transactions.map(&:contained_address_ids).flatten.uniq, + ) end def build_udts!(local_block, outputs, outputs_data) udts_attributes = Set.new + omiga_inscription_udt_attributes = Set.new + outputs.each do |tx_index, items| items.each_with_index do |output, index| - cell_type = cell_type(output.type,outputs_data[tx_index][index]) - if cell_type == "omiga_inscription_info" - info = CkbUtils.parse_omiga_inscription_info(outputs_data[tx_index][index]) - OmigaInscriptionInfo.upsert(info.merge(output.type.to_h), - unique_by: :udt_hash) - end + cell_type = cell_type(output.type, outputs_data[tx_index][index]) next unless cell_type.in?(%w(udt m_nft_token nrc_721_token spore_cell - omiga_inscription)) + omiga_inscription_info omiga_inscription)) + + type_hash, parsed_udt_type = + if cell_type == "omiga_inscription_info" + info = CkbUtils.parse_omiga_inscription_info(outputs_data[tx_index][index]) + info_type_hash = output.type.compute_hash + attrs = info.merge(output.type.to_h, type_hash: info_type_hash) + pre_closed_info = OmigaInscriptionInfo.find_by( + type_hash: info_type_hash, mint_status: :closed, + ) + attrs = + if pre_closed_info + attrs.merge(pre_udt_hash: pre_closed_info.udt_hash) + else + attrs + end + OmigaInscriptionInfo.upsert(attrs, unique_by: :udt_hash) + [info[:udt_hash], "omiga_inscription"] + else + [output.type.compute_hash, udt_type(cell_type)] + end + + if cell_type == "omiga_inscription" + omiga_inscription_udt_attributes << { type_hash:, + code_hash: output.type.code_hash, hash_type: output.type.hash_type, args: output.type.args } + end - type_hash = output.type.compute_hash unless Udt.where(type_hash:).exists? nft_token_attr = { full_name: nil, icon_file: nil, published: false, symbol: nil, decimal: nil, nrc_factory_cell_id: nil } @@ -728,16 +706,16 @@ def build_udts!(local_block, outputs, outputs_data) end nft_token_attr[:published] = true end - if cell_type == "omiga_inscription" - info = OmigaInscriptionInfo.find_by!(udt_hash: type_hash) - nft_token_attr[:full_name] = info.name - nft_token_attr[:symbol] = info.symbol - nft_token_attr[:decimal] = info.decimal + if cell_type == "omiga_inscription_info" + info = CkbUtils.parse_omiga_inscription_info(outputs_data[tx_index][index]) + nft_token_attr[:full_name] = info[:name] + nft_token_attr[:symbol] = info[:symbol] + nft_token_attr[:decimal] = info[:decimal] nft_token_attr[:published] = true end # fill issuer_address after publish the token udts_attributes << { - type_hash:, udt_type: udt_type(cell_type), block_timestamp: local_block.timestamp, args: output.type.args, + type_hash:, udt_type: parsed_udt_type, block_timestamp: local_block.timestamp, args: output.type.args, code_hash: output.type.code_hash, hash_type: output.type.hash_type }.merge(nft_token_attr) end @@ -758,6 +736,10 @@ def build_udts!(local_block, outputs, outputs_data) unique_by: :udt_hash) end end + + if omiga_inscription_udt_attributes.present? + Udt.upsert_all(omiga_inscription_udt_attributes, unique_by: :type_hash) + end end def update_ckb_txs_rel_and_fee( @@ -855,14 +837,10 @@ def build_cells_and_locks!( lock_script_ids.each do |lock_script_id| lock_script = LockScript.find lock_script_id - contract = Contract.find_by code_hash: lock_script.code_hash - - temp_hash = { script_hash: lock_script&.script_hash, - is_contract: false } + temp_hash = { script_hash: lock_script&.script_hash, is_contract: false } if contract - temp_hash = temp_hash.merge is_contract: true, - contract_id: contract.id + temp_hash = temp_hash.merge is_contract: true, contract_id: contract.id else contract = Contract.create code_hash: lock_script.script_hash temp_hash = temp_hash.merge contract_id: contract.id @@ -879,15 +857,13 @@ def build_cells_and_locks!( type_script_ids = TypeScript.insert_all!(type_scripts_attributes).map do |e| e["id"] end + type_script_ids.each do |type_script_id| type_script = TypeScript.find(type_script_id) - temp_hash = { script_hash: type_script&.script_hash, - is_contract: false } + temp_hash = { script_hash: type_script&.script_hash, is_contract: false } contract = Contract.find_by code_hash: type_script.code_hash - if contract - temp_hash = temp_hash.merge is_contract: true, - contract_id: contract.id + temp_hash = temp_hash.merge is_contract: true, contract_id: contract.id else contract = Contract.create code_hash: type_script.script_hash temp_hash = temp_hash.merge contract_id: contract.id @@ -921,7 +897,6 @@ def build_cells_and_locks!( end end - # prev_outputs = prepare_previous_outputs(inputs) prev_outputs = nil build_cell_inputs(inputs, ckb_txs, local_block.id, cell_inputs_attributes, prev_cell_outputs_attributes, input_capacities, tags, udt_address_ids, dao_address_ids, contained_udt_ids, contained_addr_ids, @@ -940,50 +915,19 @@ def build_cells_and_locks!( [input_capacities, output_capacities] end - # def prepare_previous_outputs(inputs) - # previous_outputs = {} - # outpoints = [] - # sql = "select id, tx_hash, cell_index, cell_type, capacity, address_id, type_hash, created_at, data from cell_outputs where " - # inputs.each_value do |items| - # items.each do |item| - # if !from_cell_base?(item) - # outpoints << "(tx_hash = '\\#{item.previous_output.tx_hash.delete_prefix('0')}' and cell_index = #{item.previous_output.index}) or " - # end - # end - # end - # block_number = local_cache.read("BlockNumber") - # # not just cellbase in inputs - # if inputs.size > 1 - # outpoints.each_slice(100) do |ops| - # inner_sql = sql.dup - # ops.each do |op| - # inner_sql << op - # end - # inner_sql.delete_suffix!("or ") - # CellOutput.find_by_sql(inner_sql).each do |item| - # previous_outputs["#{item.tx_hash}-#{item.cell_index}"] = item - # local_cache.push("NodeData/#{block_number}/ContainedAddresses", Address.where(id: item.address_id).select(:id, :created_at).first!) - # end - # end - # end - # previous_outputs - # end - def build_addresses!(outputs, local_block) block_number = local_cache.read("BlockNumber") outputs.each_value do |items| items.each do |item| address = local_cache.fetch("NodeData/Address/#{item.lock.code_hash}-#{item.lock.hash_type}-#{item.lock.args}") do - # TODO use LockScript.where(script_hash: output.lock.compute_hash).select(:id)&.first replace search by code_hash, hash_type and args query after script_hash has been filled - lock_script = LockScript.find_by(code_hash: item.lock.code_hash, hash_type: item.lock.hash_type, - args: item.lock.args) - Address.find_or_create_address(item.lock, local_block.timestamp, - lock_script.id) + lock_script = LockScript.find_by(code_hash: item.lock.code_hash, hash_type: item.lock.hash_type, args: item.lock.args) + Address.find_or_create_address(item.lock, local_block.timestamp, lock_script.id) end - local_cache.push("NodeData/#{block_number}/ContainedAddresses", - Address.new(id: address.id, - created_at: address.created_at)) + local_cache.push( + "NodeData/#{block_number}/ContainedAddresses", + Address.new(id: address.id, created_at: address.created_at) + ) end end end @@ -1013,26 +957,23 @@ def build_scripts(outputs) block_number = local_cache.read("BlockNumber") outputs.each_value do |items| items.each do |output| - unless local_cache.read("NodeData/#{block_number}/Lock/#{output.lock.code_hash}-#{output.lock.hash_type}-#{output.lock.args}") + lock_cache_key = "NodeData/#{block_number}/Lock/#{output.lock.code_hash}-#{output.lock.hash_type}-#{output.lock.args}" + unless local_cache.read(lock_cache_key) script_hash = output.lock.compute_hash - # TODO use LockScript.where(script_hash: script_hash).exists? replace search by code_hash, hash_type and args query after script_hash has been filled - unless LockScript.where(code_hash: output.lock.code_hash, hash_type: output.lock.hash_type, - args: output.lock.args).exists? + unless LockScript.where(code_hash: output.lock.code_hash, hash_type: output.lock.hash_type, args: output.lock.args).exists? locks_attributes << script_attributes(output.lock, script_hash) - local_cache.write( - "NodeData/#{block_number}/Lock/#{output.lock.code_hash}-#{output.lock.hash_type}-#{output.lock.args}", true - ) + local_cache.write(lock_cache_key, true) end end - if output.type.present? && !local_cache.read("NodeData/#{block_number}/Type/#{output.type.code_hash}-#{output.type.hash_type}-#{output.type.args}") - script_hash = output.type.compute_hash - # TODO use TypeScript.where(script_hash: script_hash).exists? replace search by code_hash, hash_type and args query after script_hash has been filled - unless TypeScript.where(code_hash: output.type.code_hash, hash_type: output.type.hash_type, - args: output.type.args).exists? - types_attributes << script_attributes(output.type, script_hash) - local_cache.write( - "NodeData/#{block_number}/Type/#{output.type.code_hash}-#{output.type.hash_type}-#{output.type.args}", true - ) + + if output.type.present? + type_cache_key = "NodeData/#{block_number}/Type/#{output.type.code_hash}-#{output.type.hash_type}-#{output.type.args}" + if !local_cache.read(type_cache_key) + script_hash = output.type.compute_hash + unless TypeScript.where(code_hash: output.type.code_hash, hash_type: output.type.hash_type, args: output.type.args).exists? + types_attributes << script_attributes(output.type, script_hash) + local_cache.write(type_cache_key, true) + end end end end @@ -1320,7 +1261,6 @@ def build_ckb_transactions!(node_block, local_block, inputs, outputs, end header_deps[tx.hash] = tx.header_deps witnesses[tx.hash] = tx.witnesses - tx_cell_deps[tx.hash] = tx.cell_deps ckb_transactions_attributes << attrs hashes << tx.hash diff --git a/app/models/omiga_inscription_info.rb b/app/models/omiga_inscription_info.rb index bd0ad4629..98cdb2550 100644 --- a/app/models/omiga_inscription_info.rb +++ b/app/models/omiga_inscription_info.rb @@ -22,6 +22,8 @@ class OmigaInscriptionInfo < ApplicationRecord # udt_id :bigint # created_at :datetime not null # updated_at :datetime not null +# type_hash :binary +# pre_udt_hash :binary # # Indexes # diff --git a/app/serializers/udt_serializer.rb b/app/serializers/udt_serializer.rb index 20aa93b9c..223dc8f17 100644 --- a/app/serializers/udt_serializer.rb +++ b/app/serializers/udt_serializer.rb @@ -43,4 +43,16 @@ class UdtSerializer } do |object| object.omiga_inscription_info.args end + + attribute :info_type_hash, if: Proc.new { |record, _params| + record.udt_type == "omiga_inscription" + } do |object| + object.omiga_inscription_info.type_hash + end + + attribute :pre_udt_hash, if: Proc.new { |record, _params| + record.udt_type == "omiga_inscription" + } do |object| + object.omiga_inscription_info.pre_udt_hash + end end diff --git a/app/workers/generate_cell_dependencies_worker.rb b/app/workers/generate_cell_dependencies_worker.rb new file mode 100644 index 000000000..fdd191131 --- /dev/null +++ b/app/workers/generate_cell_dependencies_worker.rb @@ -0,0 +1,21 @@ +class GenerateCellDependenciesWorker + include Sidekiq::Worker + + def perform(block_id) + block = Block.find_by(id: block_id) + return unless block + + tx_cell_deps = build_cell_deps(block.number) + block.ckb_transactions.each do |txs| + DeployedCell.create_initial_data_for_ckb_transaction(txs, tx_cell_deps[txs.tx_hash]) + ReferringCell.create_initial_data_for_ckb_transaction(txs) + end + end + + def build_cell_deps(number) + node_block = CkbSync::Api.instance.get_block_by_number(number) + node_block.transactions.each_with_object({}) do |tx, deps| + deps[tx.hash] = tx.cell_deps + end + end +end diff --git a/db/migrate/20240118103947_add_type_hash_to_omiga_inscription_info.rb b/db/migrate/20240118103947_add_type_hash_to_omiga_inscription_info.rb new file mode 100644 index 000000000..f343a727f --- /dev/null +++ b/db/migrate/20240118103947_add_type_hash_to_omiga_inscription_info.rb @@ -0,0 +1,5 @@ +class AddTypeHashToOmigaInscriptionInfo < ActiveRecord::Migration[7.0] + def change + add_column :omiga_inscription_infos, :type_hash, :binary + end +end diff --git a/db/migrate/20240119131328_add_pre_udt_hash_to_omiga_inscription_info.rb b/db/migrate/20240119131328_add_pre_udt_hash_to_omiga_inscription_info.rb new file mode 100644 index 000000000..c14765135 --- /dev/null +++ b/db/migrate/20240119131328_add_pre_udt_hash_to_omiga_inscription_info.rb @@ -0,0 +1,5 @@ +class AddPreUdtHashToOmigaInscriptionInfo < ActiveRecord::Migration[7.0] + def change + add_column :omiga_inscription_infos, :pre_udt_hash, :binary + end +end diff --git a/db/structure.sql b/db/structure.sql index 4ac02264f..a0e72caf9 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1668,7 +1668,9 @@ CREATE TABLE public.omiga_inscription_infos ( mint_status integer, udt_id bigint, created_at timestamp(6) without time zone NOT NULL, - updated_at timestamp(6) without time zone NOT NULL + updated_at timestamp(6) without time zone NOT NULL, + type_hash bytea, + pre_udt_hash bytea ); @@ -4816,6 +4818,8 @@ INSERT INTO "schema_migrations" (version) VALUES ('20230918033957'), ('20231017074221'), ('20231218082938'), -('20240107100346'); +('20240107100346'), +('20240118103947'), +('20240119131328'); diff --git a/test/controllers/api/v1/omiga_inscriptions_controller_test.rb b/test/controllers/api/v1/omiga_inscriptions_controller_test.rb index 07bd27b88..0c025569f 100644 --- a/test/controllers/api/v1/omiga_inscriptions_controller_test.rb +++ b/test/controllers/api/v1/omiga_inscriptions_controller_test.rb @@ -11,6 +11,32 @@ class OmigaInscriptionsControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "should return pre udt when call show" do + udt = create(:udt, :omiga_inscription) + udt.omiga_inscription_info.update(mint_status: :closed) + new_udt = create(:udt, udt_type: :omiga_inscription) + info = create(:omiga_inscription_info, udt_id: new_udt.id, + mint_status: :rebase_start, pre_udt_hash: udt.omiga_inscription_info.udt_hash, udt_hash: "0x#{SecureRandom.hex(32)}") + + valid_get api_v1_omiga_inscription_url(info.type_hash, status: "closed") + assert_equal udt.type_hash, + JSON.parse(response.body)["data"]["attributes"]["type_hash"] + end + + test "should return current rebase_start udt when call show" do + udt = create(:udt, :omiga_inscription, + block_timestamp: (Time.now - 10.minutes).to_i * 1000) + udt.omiga_inscription_info.update(mint_status: :closed) + new_udt = create(:udt, udt_type: :omiga_inscription, + block_timestamp: Time.now.to_i * 1000) + info = create(:omiga_inscription_info, udt_id: new_udt.id, + mint_status: :rebase_start, pre_udt_hash: udt.omiga_inscription_info.udt_hash, udt_hash: "0x#{SecureRandom.hex(32)}") + + valid_get api_v1_omiga_inscription_url(info.type_hash) + assert_equal new_udt.type_hash, + JSON.parse(response.body)["data"]["attributes"]["type_hash"] + end + test "should set right content type when call show" do udt = create(:udt, :omiga_inscription) @@ -46,7 +72,21 @@ class OmigaInscriptionsControllerTest < ActionDispatch::IntegrationTest assert_equal %w( symbol full_name display_name uan total_amount addresses_count decimal icon_file h24_ckb_transactions_count created_at description - published type_hash type_script issuer_address mint_status mint_limit expected_supply inscription_info_id udt_type + published type_hash type_script issuer_address mint_status mint_limit expected_supply inscription_info_id udt_type pre_udt_hash info_type_hash + ).sort, + response_udt["attributes"].keys.sort + end + + test "should contain right keys in the serialized object when query info type hash" do + udt = create(:udt, :omiga_inscription) + + valid_get api_v1_omiga_inscription_url(udt.omiga_inscription_info.type_hash) + + response_udt = json["data"] + assert_equal %w( + symbol full_name display_name uan total_amount addresses_count + decimal icon_file h24_ckb_transactions_count created_at description + published type_hash type_script issuer_address mint_status mint_limit expected_supply inscription_info_id udt_type pre_udt_hash info_type_hash ).sort, response_udt["attributes"].keys.sort end @@ -75,6 +115,18 @@ class OmigaInscriptionsControllerTest < ActionDispatch::IntegrationTest assert_equal 2, json["data"].length end + test "should return rebase_start omiga_inscription udts" do + udt = create(:udt, :omiga_inscription) + udt.omiga_inscription_info.update(mint_status: :closed) + new_udt = create(:udt, udt_type: :omiga_inscription) + create(:omiga_inscription_info, udt_id: new_udt.id, + mint_status: :rebase_start, pre_udt_hash: udt.omiga_inscription_info.udt_hash, udt_hash: "0x#{SecureRandom.hex(32)}") + + valid_get api_v1_omiga_inscriptions_url + + assert_equal 1, json["data"].length + end + test "should sorted by mint_status asc when sort param is mint_status" do page = 1 page_size = 5 diff --git a/test/factories/omiga_inscription_info.rb b/test/factories/omiga_inscription_info.rb index cd03b64e9..dab220064 100644 --- a/test/factories/omiga_inscription_info.rb +++ b/test/factories/omiga_inscription_info.rb @@ -1,5 +1,17 @@ FactoryBot.define do factory :omiga_inscription_info do - udt_hash { "0x#{SecureRandom.hex(32)}" } + udt_hash do + "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908" + end + code_hash do + "0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6" + end + hash_type { "type" } + args do + "0xcd89d8f36593a9a82501c024c5cdc4877ca11c5b3d5831b3e78334aecb978f0d" + end + type_hash do + "0x5cfcab1fc499de7d33265b04d2de9cf2f91cc7c7a578642993b0912b31b6cf39" + end end end diff --git a/test/factories/udt.rb b/test/factories/udt.rb index bd8eb033c..cb9b6ff57 100644 --- a/test/factories/udt.rb +++ b/test/factories/udt.rb @@ -44,6 +44,7 @@ code_hash: "0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6", hash_type: "type", args: "0xcd89d8f36593a9a82501c024c5cdc4877ca11c5b3d5831b3e78334aecb978f0d", + type_hash: "0x5cfcab1fc499de7d33265b04d2de9cf2f91cc7c7a578642993b0912b31b6cf39", decimal: udt.decimal, name: udt.full_name, symbol: udt.symbol, diff --git a/test/models/address_test.rb b/test/models/address_test.rb index 853d5d833..dbbf49074 100644 --- a/test/models/address_test.rb +++ b/test/models/address_test.rb @@ -8,9 +8,10 @@ class AddressTest < ActiveSupport::TestCase CkbSync::Api.any_instance.stubs(:get_block_cycles).returns( [ "0x100", "0x200", "0x300", "0x400", "0x500", "0x600", "0x700", "0x800", "0x900" - ] + ], ) GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) end context "associations" do @@ -25,11 +26,12 @@ class AddressTest < ActiveSupport::TestCase compact_target: "0x1000", length: "0x07d0", number: "0x0", - start_number: "0x0" - ) + start_number: "0x0", + ), ) - VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", record: :new_episodes) do + VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", + record: :new_episodes) do node_block = CkbSync::Api.instance.get_block_by_number(DEFAULT_NODE_BLOCK_NUMBER) create(:block, :with_block_hash, number: node_block.header.number - 1) tx = node_block.transactions.first @@ -50,16 +52,18 @@ class AddressTest < ActiveSupport::TestCase compact_target: "0x1000", length: "0x07d0", number: "0x0", - start_number: "0x0" - ) + start_number: "0x0", + ), ) - VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", record: :new_episodes) do + VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", + record: :new_episodes) do node_block = CkbSync::Api.instance.get_block_by_number(DEFAULT_NODE_BLOCK_NUMBER) create(:block, :with_block_hash, number: node_block.header.number - 1) tx = node_block.transactions.first output = tx.outputs.first - output.lock.instance_variable_set(:@args, "0xabcbce98a758f130d34da522623d7e56705bddfe0dc4781bd2331211134a19a6") + output.lock.instance_variable_set(:@args, + "0xabcbce98a758f130d34da522623d7e56705bddfe0dc4781bd2331211134a19a6") output.lock.instance_variable_set(:@code_hash, Settings.code_hash) CkbSync::NewNodeDataProcessor.new.process_block(node_block) @@ -78,21 +82,24 @@ class AddressTest < ActiveSupport::TestCase compact_target: "0x1000", length: "0x07d0", number: "0x0", - start_number: "0x0" - ) + start_number: "0x0", + ), ) - VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", record: :new_episodes) do + VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}", + record: :new_episodes) do node_block = CkbSync::Api.instance.get_block_by_number(DEFAULT_NODE_BLOCK_NUMBER) create(:block, :with_block_hash, number: node_block.header.number - 1) tx = node_block.transactions.first output = tx.outputs.first - output.lock.instance_variable_set(:@args, "0xabcbce98a758f130d34da522623d7e56705bddfe0dc4781bd2331211134a19a6") + output.lock.instance_variable_set(:@args, + "0xabcbce98a758f130d34da522623d7e56705bddfe0dc4781bd2331211134a19a6") output.lock.instance_variable_set(:@code_hash, Settings.code_hash) CkbSync::NewNodeDataProcessor.new.process_block(node_block) lock_script = node_block.transactions.first.outputs.first.lock - address = Address.find_or_create_address(lock_script, node_block.header.timestamp) + address = Address.find_or_create_address(lock_script, + node_block.header.timestamp) assert_equal output.lock.compute_hash, address.lock_hash end @@ -125,21 +132,22 @@ class AddressTest < ActiveSupport::TestCase dao: previous_output_block.dao) nervos_dao_withdrawing_block = create(:block, :with_block_hash, dao: "0x9a7a7ce1f34c6a332d147991f0602400aaf7346eb06bfc0000e2abc108760207", timestamp: CkbUtils.time_in_milliseconds(Time.current)) - nervos_dao_withdrawing_tx = create(:ckb_transaction, block: nervos_dao_withdrawing_block) + nervos_dao_withdrawing_tx = create(:ckb_transaction, + block: nervos_dao_withdrawing_block) create(:cell_input, block: nervos_dao_withdrawing_block, previous_output: { tx_hash: previous_output_tx.tx_hash, - index: 0 + index: 0, }, ckb_transaction: nervos_dao_withdrawing_tx) create(:cell_input, block: nervos_dao_withdrawing_block, previous_output: { tx_hash: previous_output_tx.tx_hash, - index: 1 + index: 1, }, ckb_transaction: nervos_dao_withdrawing_tx) create(:cell_output, block: nervos_dao_withdrawing_block, - address: address, + address:, cell_type: "nervos_dao_withdrawing", ckb_transaction: nervos_dao_withdrawing_tx, capacity: 10000 * 10**8, @@ -147,7 +155,7 @@ class AddressTest < ActiveSupport::TestCase cell_index: 0, dao: nervos_dao_withdrawing_block.dao) create(:cell_output, block: nervos_dao_withdrawing_block, - address: address, + address:, cell_type: "nervos_dao_withdrawing", ckb_transaction: nervos_dao_withdrawing_tx, capacity: 20000 * 10**8, @@ -156,7 +164,7 @@ class AddressTest < ActiveSupport::TestCase dao: nervos_dao_withdrawing_block.dao) deposit_cell = create(:cell_output, block: deposit_block, - address: address, cell_type: "nervos_dao_deposit", + address:, cell_type: "nervos_dao_deposit", capacity: 60000 * 10**8, ckb_transaction: deposit_tx, cell_index: 0, @@ -168,22 +176,24 @@ class AddressTest < ActiveSupport::TestCase tip_dao_ar_i = 10239685510632493 expected_unmade_dao_interests = (deposit_cell.capacity - deposit_cell.occupied_capacity).to_i * tip_dao_ar_i / parse_dao_ar_i - (deposit_cell.capacity - deposit_cell.occupied_capacity) - assert_equal (expected_phase1_dao_interests + expected_unmade_dao_interests), address.cal_unclaimed_compensation + assert_equal (expected_phase1_dao_interests + expected_unmade_dao_interests).to_i, + address.cal_unclaimed_compensation end test "#custom_ckb_transactions should return correct ckb transactions" do address = create(:address) block = create(:block) - ckb_transactions = create_list(:ckb_transaction, 30, block: block, address: address, + ckb_transactions = create_list(:ckb_transaction, 30, block:, address:, contained_address_ids: [address.id]) ckb_transactions.each do |tx| - AccountBook.find_or_create_by(address: address, ckb_transaction: tx) + AccountBook.find_or_create_by(address:, ckb_transaction: tx) end ckb_transaction_ids = address.account_books.select(:ckb_transaction_id).distinct expected_ckb_transactions = CkbTransaction.where(id: ckb_transaction_ids).recent - assert_equal expected_ckb_transactions.pluck(:id), address.custom_ckb_transactions.recent.pluck(:id) + assert_equal expected_ckb_transactions.pluck(:id), + address.custom_ckb_transactions.recent.pluck(:id) end test "#ckb_dao_transactions should return correct ckb transactions with dao cell" do @@ -192,13 +202,16 @@ class AddressTest < ActiveSupport::TestCase 30.times do |number| block = create(:block, :with_block_hash) contained_address_ids = number % 2 == 0 ? [address.id] : [address1.id] - tx = create(:ckb_transaction, block: block, tags: ["dao"], contained_dao_address_ids: contained_address_ids, - contained_address_ids: contained_address_ids) - AccountBook.find_or_create_by(address_id: contained_address_ids[0], ckb_transaction: tx) - AddressDaoTransaction.insert({ address_id: contained_address_ids[0], ckb_transaction_id: tx.id }) + tx = create(:ckb_transaction, block:, tags: ["dao"], contained_dao_address_ids: contained_address_ids, + contained_address_ids:) + AccountBook.find_or_create_by(address_id: contained_address_ids[0], + ckb_transaction: tx) + AddressDaoTransaction.insert({ address_id: contained_address_ids[0], + ckb_transaction_id: tx.id }) cell_type = number % 2 == 0 ? "nervos_dao_deposit" : "nervos_dao_withdrawing" cell_output_address = number % 2 == 0 ? address : address1 - create(:cell_output, block: block, address: cell_output_address, ckb_transaction: tx, cell_type: cell_type) + create(:cell_output, block:, address: cell_output_address, + ckb_transaction: tx, cell_type:) end ckb_transaction_ids = address.cell_outputs.where(cell_type: %w( @@ -207,7 +220,8 @@ class AddressTest < ActiveSupport::TestCase )).select("ckb_transaction_id").distinct expected_ckb_transactions = CkbTransaction.where(id: ckb_transaction_ids).recent - assert_equal expected_ckb_transactions.pluck(:id).sort, address.ckb_dao_transactions.recent.pluck(:id).sort + assert_equal expected_ckb_transactions.pluck(:id).sort, + address.ckb_dao_transactions.recent.pluck(:id).sort end test "#ckb_dao_transactions should return an empty array when there aren't dao cell" do @@ -222,19 +236,19 @@ class AddressTest < ActiveSupport::TestCase 30.times do |number| block = create(:block, :with_block_hash) if number % 2 == 0 - tx = create(:ckb_transaction, block: block, tags: ["udt"], contained_udt_ids: [udt.id], + tx = create(:ckb_transaction, block:, tags: ["udt"], contained_udt_ids: [udt.id], udt_address_ids: [address.id], contained_address_ids: [address.id]) - create(:cell_output, block: block, ckb_transaction: tx, cell_type: "udt", type_hash: udt.type_hash, - address: address) + create(:cell_output, block:, ckb_transaction: tx, cell_type: "udt", type_hash: udt.type_hash, + address:) else - tx = create(:ckb_transaction, block: block, tags: ["udt"], contained_udt_ids: [udt.id], + tx = create(:ckb_transaction, block:, tags: ["udt"], contained_udt_ids: [udt.id], udt_address_ids: [address.id], contained_address_ids: [address.id]) - tx1 = create(:ckb_transaction, block: block, tags: ["udt"], contained_udt_ids: [udt.id], + tx1 = create(:ckb_transaction, block:, tags: ["udt"], contained_udt_ids: [udt.id], udt_address_ids: [address.id], contained_address_ids: [address.id]) - create(:cell_output, block: block, ckb_transaction: tx1, cell_type: "udt", type_hash: udt.type_hash, - address: address) - create(:cell_output, block: block, ckb_transaction: tx, cell_type: "udt", type_hash: udt.type_hash, - consumed_by_id: tx1, address: address) + create(:cell_output, block:, ckb_transaction: tx1, cell_type: "udt", type_hash: udt.type_hash, + address:) + create(:cell_output, block:, ckb_transaction: tx, cell_type: "udt", type_hash: udt.type_hash, + consumed_by_id: tx1, address:) end end @@ -269,7 +283,8 @@ class AddressTest < ActiveSupport::TestCase ckb_transaction_ids = CellOutput.select("ckb_transaction_id").from("(#{sql}) as cell_outputs") expected_ckb_transactions = CkbTransaction.where(id: ckb_transaction_ids.distinct).recent - assert_equal expected_ckb_transactions.pluck(:id), address.ckb_udt_transactions(udt.id).recent.pluck(:id) + assert_equal expected_ckb_transactions.pluck(:id), + address.ckb_udt_transactions(udt.id).recent.pluck(:id) end test "#ckb_udt_transactions should return an empty array when there aren't udt cells" do @@ -290,7 +305,7 @@ class AddressTest < ActiveSupport::TestCase Rails.stubs(:cache).returns(redis_cache_store) Rails.cache.extend(CacheRealizer) lock_script = CKB::Types::Script.new( - code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99" + code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99", ) addr = CKB::Address.new(lock_script).generate full_addr = CKB::Address.new(lock_script).send(:generate_full_payload_address) @@ -306,7 +321,7 @@ class AddressTest < ActiveSupport::TestCase Rails.stubs(:cache).returns(redis_cache_store) Rails.cache.extend(CacheRealizer) lock_script = CKB::Types::Script.new( - code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99" + code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99", ) addr = CKB::Address.new(lock_script).generate full_addr = CKB::Address.new(lock_script).send(:generate_full_payload_address) @@ -331,7 +346,7 @@ class AddressTest < ActiveSupport::TestCase Rails.stubs(:cache).returns(redis_cache_store) Rails.cache.extend(CacheRealizer) lock_script = CKB::Types::Script.new( - code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99" + code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99", ) addr = CKB::Address.new(lock_script).generate address = Address.cached_find(addr) @@ -344,7 +359,7 @@ class AddressTest < ActiveSupport::TestCase Rails.stubs(:cache).returns(redis_cache_store) Rails.cache.extend(CacheRealizer) lock_script = CKB::Types::Script.new( - code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99" + code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99", ) full_addr = CKB::Address.new(lock_script).send(:generate_full_payload_address) address = Address.find_or_create_address(lock_script, Time.current.to_i) @@ -355,7 +370,7 @@ class AddressTest < ActiveSupport::TestCase test "#find_or_create_by_address_hash" do lock_script = CKB::Types::Script.new( - code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99" + code_hash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", hash_type: "type", args: "0xdde7801c073dfb3464c7b1f05b806bb2bbb84e99", ) lock_hash = lock_script.compute_hash full_addr = CkbUtils.generate_address(lock_script) diff --git a/test/models/block_test.rb b/test/models/block_test.rb index 82355a38d..15058b3d6 100644 --- a/test/models/block_test.rb +++ b/test/models/block_test.rb @@ -6,6 +6,7 @@ class BlockTest < ActiveSupport::TestCase create(:table_record_count, :ckb_transactions_counter) CkbSync::Api.any_instance.stubs(:get_blockchain_info).returns(OpenStruct.new(chain: "ckb_testnet")) GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) CkbSync::Api.any_instance.stubs(:get_block_cycles).returns( [ "0x100", "0x200", "0x300", "0x400", "0x500", "0x600", "0x700", "0x800", "0x900" diff --git a/test/models/ckb_sync/dao_events_test.rb b/test/models/ckb_sync/dao_events_test.rb index 37f08d42e..9477b01a2 100644 --- a/test/models/ckb_sync/dao_events_test.rb +++ b/test/models/ckb_sync/dao_events_test.rb @@ -16,6 +16,7 @@ class DaoEventsTest < ActiveSupport::TestCase create(:table_record_count, :ckb_transactions_counter) CkbSync::Api.any_instance.stubs(:get_blockchain_info).returns(OpenStruct.new(chain: "ckb_testnet")) GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) CkbSync::Api.any_instance.stubs(:get_block_cycles).returns( [ "0x100", "0x200", "0x300", "0x400", "0x500", "0x600", "0x700", "0x800", "0x900" diff --git a/test/models/ckb_sync/node_data_processor_test.rb b/test/models/ckb_sync/node_data_processor_test.rb index 8726562dc..68d49aefc 100644 --- a/test/models/ckb_sync/node_data_processor_test.rb +++ b/test/models/ckb_sync/node_data_processor_test.rb @@ -20,6 +20,7 @@ class NodeDataProcessorTest < ActiveSupport::TestCase create(:table_record_count, :ckb_transactions_counter) CkbSync::Api.any_instance.stubs(:get_blockchain_info).returns(OpenStruct.new(chain: "ckb_testnet")) GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) CkbSync::Api.any_instance.stubs(:get_blockchain_info).returns(OpenStruct.new(chain: "ckb_testnet")) end @@ -4002,7 +4003,7 @@ class NodeDataProcessorTest < ActiveSupport::TestCase assert_equal "R+K V1 N1", old_factory_cell.reload.symbol end - test "save omiga inscription info" do + test "save omiga inscription info and init udt" do CkbSync::Api.any_instance.stubs(:xudt_code_hash).returns("0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb") CkbSync::Api.any_instance.stubs(:omiga_inscription_info_code_hash).returns("0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6") VCR.use_cassette("blocks/31") do @@ -4041,11 +4042,14 @@ class NodeDataProcessorTest < ActiveSupport::TestCase assert_equal info.expected_supply, 0.21e16 assert_equal info.mint_limit, 0.1e12 assert_equal info.mint_status, "minting" - assert_equal info.udt_id, nil + assert_equal info.udt_id, Udt.first.id + assert_equal "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908", + Udt.first.type_hash end end test "save omiga inscription udt" do + CkbSync::Api.any_instance.stubs(:mode).returns("testnet") CkbSync::Api.any_instance.stubs(:xudt_code_hash).returns("0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb") CkbSync::Api.any_instance.stubs(:omiga_inscription_info_code_hash).returns("0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6") @@ -4068,6 +4072,8 @@ class NodeDataProcessorTest < ActiveSupport::TestCase cell_type: "normal", lock_script_id: address1_lock.id, type_script_id: nil) + udt = create(:udt, code_hash: "0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6", hash_type: "type", args: "0xcd89d8f36593a9a82501c024c5cdc4877ca11c5b3d5831b3e78334aecb978f0d", + type_hash: "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908", udt_type: "omiga_inscription") info = create(:omiga_inscription_info, code_hash: "0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6", hash_type: "type", @@ -4079,17 +4085,66 @@ class NodeDataProcessorTest < ActiveSupport::TestCase expected_supply: 0.21e16, mint_limit: 0.1e12, mint_status: "minting", - udt_id: nil) + udt_id: udt.id) + node_data_processor.process_block(node_block) assert_equal CellOutput.find_by(type_hash: info.udt_hash).udt_amount, 0.1e12 assert_equal 1, UdtAccount.count assert_equal 0.1e12, UdtAccount.first.amount assert_equal 1, UdtTransaction.count - omiga_inscription = Udt.first - assert_equal OmigaInscriptionInfo.first.udt_id, omiga_inscription.id - assert_equal omiga_inscription.type_hash, + assert_equal OmigaInscriptionInfo.first.udt_id, udt.id + assert_equal udt.reload.type_hash, "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908" + assert_equal "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", + udt.reload.code_hash + end + end + + test "change omiga inscription to rebase_start" do + CkbSync::Api.any_instance.stubs(:mode).returns("testnet") + CkbSync::Api.any_instance.stubs(:xudt_code_hash).returns("0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb") + CkbSync::Api.any_instance.stubs(:omiga_inscription_info_code_hash).returns("0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6") + + VCR.use_cassette("blocks/33") do + node_block = CkbSync::Api.instance.get_block_by_number(33) + block1 = create(:block, :with_block_hash, + number: node_block.header.number - 1) + tx1 = create(:ckb_transaction, block: block1, + tx_hash: "0x3e89753ebca825e1504498eb18b56576d5b7eff59fe033346a10ab9e8ca359a4") + input_address1 = create(:address) + address1_lock = create(:lock_script, address_id: input_address1.id, + args: "0x#{SecureRandom.hex(20)}", + code_hash: Settings.secp_cell_type_hash, + hash_type: "type") + output1 = create(:cell_output, ckb_transaction: tx1, + block: block1, capacity: 50000000 * 10**8, + tx_hash: tx1.tx_hash, + cell_index: 1, + address: input_address1, + cell_type: "omiga_inscription_info", + lock_script_id: address1_lock.id, + type_script_id: nil) + + udt = create(:udt, code_hash: "0x25c29dc317811a6f6f3985a7a9ebc4838bd388d19d0feeecf0bcd60f6c0975bb", hash_type: "type", args: "0x9709d30fc21348ae1d28a197310a80aec3b8cdb5c93814d5e240f9fba85b76af", + type_hash: "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908", udt_type: "omiga_inscription") + info = create(:omiga_inscription_info, + code_hash: "0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6", + hash_type: "type", + args: "0xcd89d8f36593a9a82501c024c5cdc4877ca11c5b3d5831b3e78334aecb978f0d", + type_hash: "0x5cfcab1fc499de7d33265b04d2de9cf2f91cc7c7a578642993b0912b31b6cf39", + decimal: 0.8e1, + name: "CKB Fist Inscription", + symbol: "CKBI", + udt_hash: "0x5fa66c8d5f43914f85d3083e0529931883a5b0a14282f891201069f1b5067908", + expected_supply: 0.21e16, + mint_limit: 0.1e12, + mint_status: "closed", + udt_id: udt.id) + + node_data_processor.process_block(node_block) + assert_equal 2, Udt.count + assert_equal info.udt_hash, OmigaInscriptionInfo.last.pre_udt_hash end end diff --git a/test/models/ckb_transaction_test.rb b/test/models/ckb_transaction_test.rb index 85f51f714..0bed44893 100644 --- a/test/models/ckb_transaction_test.rb +++ b/test/models/ckb_transaction_test.rb @@ -27,6 +27,7 @@ class CkbTransactionTest < ActiveSupport::TestCase test "#tx_hash should decodes packed string" do GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) VCR.use_cassette("blocks/#{DEFAULT_NODE_BLOCK_NUMBER}") do CkbSync::Api.any_instance.stubs(:get_epoch_by_number).returns( CKB::Types::Epoch.new( diff --git a/test/models/lock_script_test.rb b/test/models/lock_script_test.rb index 7159d3e8e..e599313a0 100644 --- a/test/models/lock_script_test.rb +++ b/test/models/lock_script_test.rb @@ -6,6 +6,7 @@ class LockScriptTest < ActiveSupport::TestCase create(:table_record_count, :ckb_transactions_counter) CkbSync::Api.any_instance.stubs(:get_blockchain_info).returns(OpenStruct.new(chain: "ckb_testnet")) GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) CkbSync::Api.any_instance.stubs(:get_block_cycles).returns( [ "0x100", "0x200", "0x300", "0x400", "0x500", "0x600", "0x700", "0x800", "0x900" diff --git a/test/models/type_script_test.rb b/test/models/type_script_test.rb index 4b883d1f2..ac94e4c24 100644 --- a/test/models/type_script_test.rb +++ b/test/models/type_script_test.rb @@ -17,6 +17,7 @@ class TypeScriptTest < ActiveSupport::TestCase test "#code_hash should decodes packed string" do GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) CkbSync::Api.any_instance.stubs(:get_epoch_by_number).returns( CKB::Types::Epoch.new( compact_target: "0x1000", diff --git a/test/models/uncle_block_test.rb b/test/models/uncle_block_test.rb index f6e275295..a749491ca 100644 --- a/test/models/uncle_block_test.rb +++ b/test/models/uncle_block_test.rb @@ -6,6 +6,7 @@ class UncleBlockTest < ActiveSupport::TestCase create(:table_record_count, :ckb_transactions_counter) CkbSync::Api.any_instance.stubs(:get_blockchain_info).returns(OpenStruct.new(chain: "ckb_testnet")) GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) CkbSync::Api.any_instance.stubs(:get_block_cycles).returns( [ "0x100", "0x200", "0x300", "0x400", "0x500", "0x600", "0x700", "0x800", "0x900" diff --git a/test/test_helper.rb b/test/test_helper.rb index 46a3839da..257bfa077 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -49,6 +49,7 @@ def prepare_node_data(node_tip_block_number = 30) Sidekiq::Testing.inline! GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) CkbSync::Api.any_instance.stubs(:get_tip_block_number).returns(node_tip_block_number + 1) CkbSync::Api.any_instance.stubs(:get_epoch_by_number).returns( CKB::Types::Epoch.new( diff --git a/test/utils/ckb_utils_test.rb b/test/utils/ckb_utils_test.rb index 82f907bd7..6a95508a3 100644 --- a/test/utils/ckb_utils_test.rb +++ b/test/utils/ckb_utils_test.rb @@ -19,6 +19,7 @@ class CkbUtilsTest < ActiveSupport::TestCase ], ) GenerateStatisticsDataWorker.any_instance.stubs(:perform).returns(true) + GenerateCellDependenciesWorker.any_instance.stubs(:perform).returns(true) end test ".generate_address should return mainnet address when mode is mainnet" do @@ -311,6 +312,7 @@ class CkbUtilsTest < ActiveSupport::TestCase end test "cell_type should return mainnet m_nft_issuer when type script code_hash match m_nft_issuer code_hash" do + ENV["CKB_NET_MODE"] = "mainnet" type_script = CKB::Types::Script.new( code_hash: Settings.mainnet_issuer_script_code_hash, hash_type: "type", args: "0x", ) @@ -318,6 +320,8 @@ class CkbUtilsTest < ActiveSupport::TestCase end test "cell_type should return mainnet m_nft_class when type script code_hash match m_nft_class code_hash" do + ENV["CKB_NET_MODE"] = "mainnet" + type_script = CKB::Types::Script.new( code_hash: Settings.mainnet_token_class_script_code_hash, hash_type: "type", args: "0x", ) @@ -325,6 +329,8 @@ class CkbUtilsTest < ActiveSupport::TestCase end test "cell_type should return mainnet m_nft_token when type script code_hash match m_nft_token code_hash" do + ENV["CKB_NET_MODE"] = "mainnet" + type_script = CKB::Types::Script.new( code_hash: Settings.mainnet_token_script_code_hash, hash_type: "type", args: "0x", ) @@ -426,7 +432,7 @@ class CkbUtilsTest < ActiveSupport::TestCase "0x02260000100000001e000000022600000a000000696d6167652f6a706567e0250000ffd8ffe000104a46494600010101012c012c0000ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828ffc000110801df01db03012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f5fa28a2bbce40a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a2b2753f1168fa6645eea36f1b8ea81b737fdf2326b97d43e28691012b676f7574c3a1c0453f89e7f4a2c349b3bea2bc7af7e29ea526459d8dac00f772d211fc87e958577e3bf115ce73a8b46be9122ae3f1033fad3e563e467bf532491231991d507ab1c57cdd73ad6a9739fb46a579267b34ec47f3aa0ccce72c4b1f52734f947eccfa5a4d574e8ffd65fda27fbd328feb509f1068cbd756d3c7d6e53fc6be6ea28e51fb33e901e21d14f4d5f4e3ff006f29fe352a6b3a649f7352b26fa4ea7fad7cd5451ca1eccfa7e2b8866ff55346ff00eeb0352d7cb756edf52bfb6c7d9ef6ea2c7fcf39597f91a3945eccfa668af9eed7c67e21b5c797aa4ed8ff009eb893ff004206b6ecbe27eb30e05cc36970bdc942adf9838fd28e562e467b4d15e6f61f156ca4c0bfd3e784fac4c241fae2ba7d37c65a0ea1810ea30a39fe09b319fa7cd807f0a56627168e868a6a32ba86460ca79041c834ea420a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a29090a0924003924d71de21f885a4697ba2b5637f7238db09f901f77e9f966804ae765589ad78a347d1b72dedec6251ff2c63f9dff0021d3f1c578f6bde39d6b57dc9f68fb2db9ff009656f95c8f73d4fe78ae5cf2726a944b50ee7a76b1f15246dc9a3d8aa0ed25c1c9ff00be474fccd715aaf89f59d5770bcd427643d6343b13f218158d45558b514828a28a0a0a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2802f69babea1a636ed3ef27b7ef847201fa8e86bb2d23e27ea76fb5752b786f13bb2feedff004e3f4af3fa28b09a4cf7ad17c79a1ea9b50dcfd9263fc173f27e4dd3f5aea548650ca410790477af972b6344f126ada2b0fb05e48b18eb137cc87fe027fa54b890e1d8fa328af3af0ffc4eb3b9db16b501b590f1e6c7968cfd4751fad77f697505e40b3da4d1cd0b7478d8303f88a9b58cda6b726a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28acfd6b58b1d16d0dc6a33ac49fc23ab39f403b9a00d0ae4fc51e39d2f43df0a37daef471e4c47853fed3741f4e4fb579ef8b3e205feafbedf4fdd656478f94fef1c7b9edf41f99ae26a947b96a1dce83c47e2dd575e665ba9fcbb63d2de2f953f1f5fc6b9fa28aa34b5828a28a06145145001451450014514500145145001451450014514500145145001451450014514500145145001451450015a1a36b3a868d71e769d73242dfc4a0e55bea3a1acfa2811ec3e18f8956978520d6916d273c099798dbebdd7f51ef5e831c892c6af13aba30cab29c823d8d7cbb5bfe19f15ea7e1f900b597ccb6272d6f21ca1fa7a1f71fad4b890e1d8fa168ae77c2de2dd3bc4318581fc9bb032d6f21f9bea3fbc3e9fa57455266d5828a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a6bb2a233bb055519249c002bca7c73f109a632586812158feec974382dec9e83dff2f5a12b8d2b9d278cfc7569a1efb5b2db75a88e0ae7e488ff00b47d7d87e95e37ab6a779ab5e35d6a13bcd33773d00f403b0aa6492492724d15a25635514828a28a0a0a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2801d148f0cab242ec9221cab29c107d41af51f067c46cecb3f10b60fdd4bb03ff431fd7f3f5af2ca286ae4b499f5123ac88af1b0646190ca7208f514eaf08f05f8d2efc3f22c13eeb8d389e622794f74ff000e9f4eb5ed9a5ea36baa5947776132cd03f461d8fa11d8fb543563271b16e8a28a420a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a8aeae21b4b7927b991628631b9dd8e0014977730d9db49717522c5046bb9dd8f005786f8ebc5f3f88ae4c30168b4d8dbe48fa173fde6ff000ed4d2b8e31b963c77e369b5c91ecec0b43a629fa34deedededf9fb717451566c95828a28a06145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450015b5e16f11def876f84d68dba16ff5b031f9641fd0fa1ac5a2811f48787b5bb3d7b4f5bab17c8e8f19fbd1b7a115a95f37787b5bbcd07514bbb17c1e8e87eec8be86bdefc35aeda78834e5bab36c11c49113f346de87fc7bd435632946c6b514514890a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a64d2a4313cb33aa4680b3331c00075269f5e39f137c5e75199f4ad364ff00428db1348a7fd6b0ec3fd91fa9fc29a571a5733bc7fe2f93c41746dad19934c89be51d0ca7fbc7fa0ae3e8a2acd92b05145140c28a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a002b53c37ae5de81a925dd9b67b49193f2c8be87fc7b565d1408fa4f41d5ed75cd362bdb27ca370ca7aa37753ef5a35f3d7837c493f87353132ee7b4930b3c59fbc3d47b8ed5efd637705f59c57569209209543230ee2a1ab18ca3627a28a290828a28a0028a28a0028a28a0028a28a0028a2b0fc61afc5e1ed1a4ba7c34edf24119fe27ff01d4d01b9ccfc51f15ff67dbb693a7c98bb997f7cea798d0f6fa9fe5f515e3b52dddccd79752dc5cc8649a562eec7a926a2ad12b1b25641451450505145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514574da0783eefc4969249a0dcdb5d5dc4bba4b276f2a603d541f9587b839f619a52928abc82d7399a2ac5fd95d69d7725adfdbcb6d7119c3472a9561f81aaf4d3b8051451400514514005773f0cfc56747bd1a7df49ff12fb86e198f1139eff43dff003f5ae1a8a04d5cfa928af3ff00859e27fed1b2fecabd933776ebfba663cc918fea3f97e35e8159b56306ac14514500145145001451450014514500364758a3692460a8a0b33138000ea6be7ef1c7885fc43ad3cca48b48b29029feeff7bea7afe43b577bf173c43f65b25d1ed5f135c0dd3907eec7d87e27f41ef5e4355146905d428a28aa340a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800ab7a4ea377a4ea305f69f334175036e475ec7fa8ec477aa9450d5f4607d3d0da68df16bc1305d5d42b0de806332c63e7b6947500f753c1c1ea08ef5f3af89b43bcf0e6b571a66a29b6784f0c3eeba9e8cbea0d7a4fece5abbdbf88afb4a763e4ddc1e6a8f4743fd549fc8575bfb4378792f7c390eb5120fb4d8384918753131c73f4623f335e6d39bc3d7f64fe17b1a35cd1b9f3ad14515e91985145140051451401674dbd9f4ebe82f2d1f64f0b0653fd0fb57d11e1cd5e0d734882fadf8120c3a679461d56be6eaed7e177887fb2759fb15c3e2cef085393c249fc27f1e87f0f4a4d5c89aba3dbe8a28a8320a28a2800a28a2800aabaa5f43a6e9d717972db61850bb7bfb0f73d2ad5796fc64d6ff00d468d037a4d3e3ff001d5febf9534ae34aecf39d63509b55d4ee2fae4e6599cb11e83b01ec060553a28ab360a28a281851451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451401de7c0eddff000b374adbd36cdbbe9e53ff005c57d0df116149fc07e20493a0b199ff001552c3f502bc6bf672d21ee3c457daaba9f26d20f294fabb9fe8a0fe62bd4fe316a69a67c3cd5999807b8416c83fbc5ce0ff00e3bb8fe15e4629f362629791ac3489f27d14515eb990514514005145140051451401efbf0f75efeddf0fc6d3366f2dff0075367a923a37e23f5cd74f5e09f0e75bfec5f11c5e6b62d6e710cb9e8327e56fc0fe84d7bdd43563192b30a28a291214514500417b7315959cf7570db62850c8e7d80cd7cddac6a12ea9aa5cdf4e7f793b9723d0761f80c0fc2bd63e30eadf64d121d3a26c4976d97c7f7179fd4e3f235e3757146905d428a28a66814514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514aaa5982a8249e8077a004ab7a4e9d77ab6a3058e9f0b4f753b6d445ee7fa0ee4f6aea7c2df0d7c45e202922da8b2b33d6e2e8ec007b2fde3f963debd8fc3b69e0af86762ed3eab6b26a2cb8966660f337b2a2e4aafb7e64d7356c5461a435914a37dceafc05e1987c27e1ab7d36221e51fbc9e51ff002d243d4fd3a01ec057857c70f19c7e21d6a3d374e943e9b604e5d4e56597a161ea07407ebeb567e22fc5cbad760974ed0124b2d3dc159266389651e9c7dd1fa9fd2bca6b0c2e1a4a5ed6aee54a4ad641451457a06614514500145145001451450015f407c3fd67fb6bc356f2c8dbae61fdccd9ea5877fc460d7cff005ddfc22d5bec5afbd8c8d886f57033d9d791fa647e549ad089aba3da68a28a8320a28acdf126a234ad06faf720343112b9fef1e17f522803c4fe236a9fda9e2bbb656cc36e7ecf1fd17aff00e3d9ae66862598962493c927bd15a1ba560a28a28185145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140054d6773259ddc17301db2c2e2453e841c8a868a047d37a6ddc7a869f6d770ff00ab9e35917db2338ab35c27c20d4bed7e1b7b473992ce42a07fb0dc8fd777e55ddd66cc1ab30af3cf8cda8791a25a58a9c35ccbb987aaa0ff00123f2af43af11f8bb7df69f157d9c1f96d6154c7fb47e63fa11f9538ee5415d9c4d1451566c145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500771f08750fb2f89dad58e12ee22b8ff00697e61fa06fcebdb2be69d0af4e9dacd8de03810ccae7e80f23f2cd7d2a082323906a646535a8b5f36f896f3edfe20d46eb39124ee57fddcf1fa62be85d6ae7ec5a3df5d6706181e41f50a4d7cd144474c28a28aa340a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800afa37c2379f6ff000ce99704e59a050c7fda0307f506be72aecbc3fe32974ad22dec959808b774f7627fad26ae4495cf4cf89171f67f05ea4c0f2eab18ff00813007f4cd780d7b5fc619bcbf0a2203feb6e517f463fd2bc5288ec10d828a28a65851451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451401ebbf1ae4c693a747fde9d9bf25ff00ebd79157aafc6e6c43a3afab4a7f209fe35e554a3b110d828a28a65851451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451401ea5f1bf38d17d3f7dffb4ebcb6bd57e372e61d1dbd1a51f984ff000af2aa4b6221b0514514cb0a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2803d77e35c79d274e93fbb3b2fe6bffd6af22af6bf8c30f99e144703fd55ca37e8c3fad78a528ec44360a28a2996145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145007bf7c48b7fb4782f525039455907fc05813fa66bc06be97d6adbedba3df5ae326681e31f52a457cd14a2670d828a28a66814514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014515d9787fc192eaba45bdeaab112eee9ecc47f4a04dd8f72af9b7c4b67f60f106a36b8c08e770bfeee78fd315f495788fc5db1fb378abed007cb750abe7fda1f29fd00fcea626707a9c4d1451546a14514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450015f46f846cfec3e19d32dc8c32c0a587fb4464fea4d78068564751d66c6cc0c89a6543ec09e4fe59afa540006070054c8cea316bcf3e3369fe7e89697ca32d6d2ed63e8ae3fc40fcebd0eb37c49a70d5741beb2c02d34442e7fbc395fd40a94427667cdb450c0ab10c0823820f6a2b4370a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2803b8f843a7fdabc4ed74c32969116cffb4df28fd0b7e55ed95c27c20d37ec9e1b7bc75c497921607fd85e07ebbbf3aeeea1ee632776145145224f01f88da5ff0065f8aeed55710dc1fb447f46ebff008f66b99afa96386195f13451c9e9bd41a7b69960df7acad4fd625ff0af37159a7d56a7b3942ff33d1c3e17db439948f95e8afa91b45d2dbef69b647eb027f8544de1dd11bef68fa69fadaa7f8573acfa1d60fef37fecf97f31f30515f4cbf853406eba369ff840a3f90a85fc17e1c7eba3da7e0b8fe554b3da5d62ff00027ea13ee8f9b28afa31fc03e187eba4c63e9238fe4d55e4f871e176e9a7327fbb7127f56ab59e50eb17f87f98bea153ba3e7ba2bdf24f85fe1b6fbb15d27fbb31feb5564f84fa0b7ddb8d453e92a1fe6b56b3ac33eff713f51abe4786d15ed12fc22d30ff00aad46f57fde0adfd055497e0f447fd56b2ebfef5b03ffb30ad166f857f6bf064bc1d5ec791515ea52fc20ba1feab5781bfde84aff5354e5f849ad2ff00aabdd3dfeacebffb2d68b33c2bda7f992f0b557d93ce68aee26f85fe238feec76b2ffb930feb8aa337c3df13c5d74b661ea92c6dfc9ab558dc3cb69afbd10e8545f659cad15b93784bc410fdfd1af8ff00b9096fe59acf9f4ad42df3e7d85dc58fefc2cbfcc56d1ab097c324fe64b8496e8a74504104820823b1a2ac90a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28ab569a6df5e63ec765733e7fe7944cdfc850ddb702ad15d1da781bc4f758f2b43be19ff009e91f97ffa162b62d7e1478b26c799650c19ff009e9709ff00b29359bad4d6f243e57d8e128af50b6f82daebe0dc5f69b10f456763ff00a08ad4b7f82129c1b8d7517d92d49fd4b0acde2e8afb43e49763c6e8af7683e09e98b8fb46ad78ff00ee22aff3cd6843f06fc371fdf9b5297fde9947f25159bc7d15d47ece47cf3457d290fc28f09c7f7eca697fdfb87fe8455e87e1c784a2fbba3447fdf9246fe6d50f31a7d98fd933e5da2bead8fc0fe188feee87607fde8837f3ab31f857c3f1fdcd0b4b07d7ec91e7f954bcc61d22c3d933e49a2bebf4d0f494fb9a5d82fd2dd07f4a9934cb04fb9656abf48947f4a5fda4bf947ecbccf8ea8afb296da04fbb044bf44029e2341d1147e14bfb4bfbbf8ffc00f65e67c65457d9e00030060514bfb4bfbbf8ff00c00f65e67c61457d9a634230517f2a6b5bc0df7a18cfd5453fed2feefe3ff003d9799f1a515f62b69d62ff007eced9beb129fe950be89a53fdfd32c5beb6e87fa53fed25fca1ecbccf902a6b3b692f2ee0b6806e966711a8f524e057d632785f4093fd6687a5b7d6d23ff0acebef0de8360f14d67a458c1741b28f1c214afb8c5694f1d1a9251512650e5572a69b691e9fa7db5a43feae08d635f7c0c66acd145751c81451450000e0823a8abcadb9411dea8d58b57eaa7ea2bc8cdf0fed297b45bc7f23d0cbeb724f91eccb1451457cb9ed85145140051451400514514005145140051451400514514005145140114d6f0ce313451c83d1d41fe759f3f87345b8cf9da45839f536e99fcf15ab45546728fc2ec2714f7473171e02f0ccf9dfa4c4bff5cddd3f91159773f0b7c3b2e7cb5bc83feb9cd9ff00d081aeee8ade38cc44769bfbccdd0a6f78a3cc2e7e10d8367ecdaa5d47ff005d2357fe58acbb9f84178b9fb36ab6f27a799114fe44d7b22a337dd527e82a74b499ba80bf535d54f32c67495fe48c6787a0b7563e7ebaf85be22873e58b3b8ffae7363ff4202b22ebc0fe25b6cf99a45c363fe79ed93ff4126be9e4b0fefbfe42a64b4857f84b7d4d7753cc717f69239a7468746cf912eb49d46d3fe3eac2ee1ffae90b2ff3156f4ef0c6bba8e0d96917d2a9e8e2160bff007d118afad95117eeaa8fa0a75762cca76d62ae73ba4afa33e6db0f84de29ba00cb6f6d680ffcf79c7fecbbaba3b0f82372d837facc31faac1097fd491fcabdbe8aca58facf6d015389e6563f06bc3f0e0dd5cdfdcb771bd517f2033fad6fd97c38f0a5a63668f1487d6676933f83122baea2b09622acb7932b952e86759e87a55963ec7a658c18ff009e502aff00215a34515936dee505145148028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a002b9cd467f3ee9883f2afcab5b1a9cfe45b1c1f9dfe515cf57a581a5bd4672e227f6428a28af48e60a28a2800a55255811d4525149a5256609b4ee8bcac19411d0d3aaadb3e0ed3d0f4ab55f178cc33c35570e9d3d0fa4c3d655a9a9750a28a2b94dc28a28a0028a28a0028a28a0028a28a0028a28009380093ed400515623b395fa80a3deacc7651afdf258fe42b6861e72e8632af08f5338024e00c9a992d657fe1c0f7e2b51115061140fa0a7574c706bed3309629fd94514b01fc6e4fb0ab096d1274404fbf353515d11a308ec8c255672dd88060714b4515a1985145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514550d5ae7c983629f9df8fa0aba707524a289949455d999a95c7da2e4953f22f0bfe35568a2bdf845422a2ba1e7c9b93bb0a28a2a841451450014514500157217de99ee3ad53a744e51b3dbbd7066184facd3d3e25b7f91d584c47b19ebb32f5148082011d296be41ab68cfa14ee145145200a28a2800a28ab10da48fcb7c83deaa3094dda289949455db2bd4b15bc927dd5e3d4f4ad08ad638f9c6e3ea6a7aeb8613acd9cb3c57f2a29c562a39918b7b0e2ad222a0c2281f4a7515d70a7187c28e695494f761451455901451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500325758a367738551935cddcccd3ccd2377e83d055cd5aefcd7f2a33f229e4fa9aceaf5f0743923cef7671d7a9ccec828a28aed300a28a2800a28a2800a28a2800a28a28026b79369da7a1e956ab3eacc12ee1b5baf6f7af9fcd703bd7a6bd7fcff00ccf57018aff9753f97f913d145490c2f29c20e3b9ec2bc149c9d91eab692bb23ab10da3c9c9f957d4d5c82d522c13f337a9ab15db4f09d667254c4f4810c36f1c5f7464fa9eb53514576462a2ac8e47272776145145310514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400567ea977e4a79719fde30fc854f7d74b6d16e3cb9fba3d6b9e91da472ee72c4e49aeec261f9df3cb630ad539572adc6d14515eb1c61451450014514500145145001451450014514500140e0d1450069e9a12e18891b0c3f87d6b6154280140007615caa33238642430e4115bfa7deadcaed6c094751ebee2bc6af818d16e74d69fd7e07743132a9eecd9728a28ae4350a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a86eae12de22eff80f5345cce96f19790fd07735cf5d5c3dcca5dcfd07a57561b0eeabbbd8caad550565b897133cf29790f27b7a5474515eca492b2385bbeac28a28a6014514500145145001451450014514500145145001451450014a8cc8c19490c39045251401bda7dfadc00926165ffd0aaf5726090723835af61a90388ee0e0f67f5fad79789c25bdea7b763aa956be923568a28af3ce90a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a82eee52da3dce724f45ee6a2bebe4b605570d2fa7a7d6b0a591e590bc8c4b1aedc3e15d4f7a5b1855aca3a2dc75ccef7121790fd07615151457ac928ab238dbbeac28a28a601451450014514500145145001451450014514500145145001451450014514500145145005db1d41edf08f978bd3b8fa56dc32a4c81e360cb5cbd4904d240fba2620ff3ae3af848d4f7a3a336a759c747b1d451542cf518e6c2c988dfdfa1abf5e54e9ca9bb491d719292ba0a28a2a0a0a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28aad757915b0f9ce5fb28eb5518b93b4509b495d96090a0924003a935937da9f54b63f57ff000aa777792dc9f98ed4eca3a556af4e860947dea9ab396a576f4881249249c9345145779ce145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500156ed2fe5830a4ef4fee9edf4aa9454ce119ab490e32717747476d790dc708d86fee9eb566b93abb6da94d0e039f317d1bafe75e755c0bde9b3a6188fe637e8aa96f7f04d81bb637a37156eb8650941da4ac7429296a828a28a8185145140051451400514514005145140051451400514514005145140051451400514514005145413dd4300fde3807d0726aa317276484da5b93d453cf1c0bba570a3f5359573aabb6440bb07a9e4d673bb3b16762cc7b935db4b03296b3d0c27884be1346ef5477cac0362ff0078f5ff00eb5669249249249ee68a2bd1a74a34d5a28e694dcb56145145684851451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140054f05dcd07fab738f43c8a828a99454959a04dad51af0eac0f13478f75ff000abd0ddc137dc9173e87835cd515cb3c15397c3a1b46bc96fa9d6515cc4573345feae4603d339156e3d5665fbea8ff00a1ae59606a2f85dcd96222f73728acd8f5688fdf8dd7e9cd588afade4385739f420d73ca8548ef1345522f665aa2901c8c8a5ac8b0a28a2900514514005145140051504b750c3feb1f1f81aacfaac0bf755dbf0c56b1a3527b225ce2b76685158d26af21ff00571aafd4e6aa4b7b7127de9580f45e2ba2381a8f7d0c9d78ad8e8259a3887ef1d57ea6a8cdaac4bc44ace7d7a0ac52727268ae986060be2773296224f62dcfa85c4bc6ed8be8bc554a28aec8c230568ab18b9396e14514550828a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a0028a28a00ffd9" info = CkbUtils.parse_spore_cell_data(data) assert_equal info[:content_type], "image/jpeg" - assert_equal info[:cluster_id], nil + assert_nil info[:cluster_id] end test "parse omiga inscription info data" do @@ -440,7 +446,7 @@ class CkbUtilsTest < ActiveSupport::TestCase test "parse omiga inscription info data when name is null" do data = "0x08004b42204669737420496e736372697074696f6e04434b4249e0f8e095d975e21e1b451b582c9d0685104471d377c6589339b723f76c035c740040075af0750700000000000000000000e8764817000000000000000000000000" info = CkbUtils.parse_omiga_inscription_info(data) - assert_equal info[:name], nil + assert_nil info[:name] end test "parse omiga inscrpition data" do diff --git a/vcr_fixtures/vcr_cassettes/blocks/33.yml b/vcr_fixtures/vcr_cassettes/blocks/33.yml new file mode 100644 index 000000000..d5f9c3b4e --- /dev/null +++ b/vcr_fixtures/vcr_cassettes/blocks/33.yml @@ -0,0 +1,39 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:8114/ + body: + encoding: UTF-8 + string: '{"id":1,"jsonrpc":"2.0","method":"get_block_by_number","params":["0x21","0x2",false]}' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/json + Connection: + - keep-alive + Keep-Alive: + - '30' + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '2138' + Date: + - Fri, 04 Oct 2019 15:54:13 GMT + body: + encoding: UTF-8 + string: '{"jsonrpc":"2.0","result":{"extension":"0xa33703945490c0d8eb61dd564dcdce04d6ad80a8ae1aeef671354f9735ec74bb","header":{"compact_target":"0x1d08cdb1","dao":"0x4462198b0e5d5c4aad67c38868c82700749fdc3d3514d80500ec69f6012acf08","epoch":"0x70803ee001ed5","extra_hash":"0x7f28e2900ffc36be0bcbe76253ec558d5c2ce1868ba029438d7a39f514078056","hash":"0x1dcad92e8085f70ed8dc7eb3c105dbae84bd267f4f426cf265f9d959436a1287","nonce":"0x6691cc8bd17283f67f35b2bdf31fad91","number":"0x21","parent_hash":"0x96f44bbc683837c917066f7b610a6709b629604bb4a544293f45e522ae57e4b3","proposals_hash":"0x297d92aff8d62ba05f067085afe1082bc8b080883f27cfcd440be1bea1a5433e","timestamp":"0x18cba8806b7","transactions_root":"0x171dbdcf5572615f2c111f9fd3eef00304f25f482b0f1bf141bb7b742769a136","version":"0x0"},"proposals":["0xe7989e121502a9c906d1","0xb31087bf0881f23574b0"],"transactions":[{"cell_deps":[],"hash":"0xe150a92d7a15f9f85bc0fd806885b012b1c084728ef6c0f1af157fad59814f3c","header_deps":[],"inputs":[{"previous_output":{"index":"0xffffffff","tx_hash":"0x0000000000000000000000000000000000000000000000000000000000000000"},"since":"0xb3bf47"}],"outputs":[{"capacity":"0x19bf50f9db","lock":{"args":"0x0450340178ae277261a838c89f9ccb76a190ed4b","code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type"},"type":null}],"outputs_data":["0x"],"version":"0x0","witnesses":["0x830000000c00000055000000490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000da648442dbb7347e467d1d09da13e5cd3a0ef0e12a0000000000000020302e3131332e302d72633220283866663030323620323032332d31322d31392920deadbeef"]},{"cell_deps":[{"dep_type":"dep_group","out_point":{"index":"0x0","tx_hash":"0x4dcf3f3b09efac8995d6cbee87c5345e812d310094651e0c3d9a730f32dc9263"}},{"dep_type":"code","out_point":{"index":"0x0","tx_hash":"0x7bf3899cf41879ed0319bf5312c9db5bf5620fff9ebe59556c261c48f0369054"}}],"hash":"0x7046d8c5641f0cfa22bf4b2905bd4fb0e619e42bc008130a8dc743d2959fef3b","header_deps":[],"inputs":[{"previous_output":{"index":"0x1","tx_hash":"0x3e89753ebca825e1504498eb18b56576d5b7eff59fe033346a10ab9e8ca359a4"},"since":"0x0"}],"outputs":[{"capacity":"0x525430e20","lock":{"args":"0x00016091d93dbab12f16640fb3a0a8f1e77e03fbc51c","code_hash":"0xd23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac","hash_type":"type"},"type":{"args":"0xcd89d8f36593a9a82501c024c5cdc4877ca11c5b3d5831b3e78334aecb978f0d","code_hash":"0x50fdea2d0030a8d0b3d69f883b471cab2a29cae6f01923f19cecac0f27fdaaa6","hash_type":"type"}}],"outputs_data":["0x0814434b42204669737420496e736372697074696f6e04434b4249a69f54bf339dd121febe64cb0be3a2cf366a8b13ec1a5ae4bebdccb9039c7efa0040075af0750700000000000000000000e8764817000000000000000000000002"],"version":"0x0","witnesses":["0x6b010000100000006b0100006b01000057010000014599a5795423d54ab8e1f44f5c6ef5be9b1829beddb787bc732e4469d25f8c93e94afa393617f905bf1765c35dc38501a862b4b2f794a88b4f9010da02411a85e201947f9c04ff5ca1b92412f11a28d74c48339e48a192d8327738515469a877475fcd3b47c81e7d026d30b853e12bb250779a999f0aba1057e9add098f713f749960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630162f9fb777b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22596a56694d7a45325a6d5a694e4749774d3259314e474d795a6d51355a445978595756694f5745774f5455334f444a6b5a6d526a5a544a6c4d545a6d5a4755315a6a45345a4759314d4451354f4459355a6a45785967222c226f726967696e223a22687474703a2f2f6c6f63616c686f73743a38303030222c2263726f73734f726967696e223a66616c73657d"]}],"uncles":[]},"id":2} + ' + http_version: + recorded_at: Fri, 04 Oct 2019 15:54:13 GMT +recorded_with: VCR 5.0.0