Slide 1

Slide 1 text

RailsΛ ϒϩοΫνΣʔϯج൘ͷ Gatewayʹ࢖͏࿩ 2021/03/22 Fukuoka.rb 200ճLTେձ גࣜձࣾτϦΫτϥοΫɹᖂ୩

Slide 2

Slide 2 text

ࣗݾ঺հ ɹ͠Ϳ΍ɹΈ͓ ᖂ୩ɹඒॹ גࣜձࣾτϦΫτϥοΫ୅දऔక໾ Ѫ஌ݝ൒ాࢢʢాࣷʣͰϑϧϦϞʔτͷνʔϜ։ൃ ΍ͬͯ·͢ɻ ౦ւRuby࣌ʑࢀՃɻ

Slide 3

Slide 3 text

Ѫ஌ݝ஌ଟ൒ౡͰΞδϟΠϧ։ൃ΍ͬͯ·͢ɻ ʢϝϯόʔϑϧϦϞʔτʣ ίίʂ

Slide 4

Slide 4 text

ϒϩοΫνΣʔϯ/෼ࢄ୆ாͱ Railsͷ૊Έ߹Θͤ ×

Slide 5

Slide 5 text

Cordaͱ͸ • ύʔϛογϣϯܕͷ෼ࢄܕ୆ாج൫ʢϒϩοΫνΣʔϯʣ • ཁ͢ΔʹଞਓʹݟΒΕͨ͘ͳ͍΍ΓͱΓΛϒϩοΫνΣʔϯతʹ΍Δ • ଱վ᜵ੑ • εϚʔτίϯτϥΫτ

Slide 6

Slide 6 text

࡞ͬͨαʔϏε A社DB 統⼀認証基盤 A社 B社 分散台帳基盤 p2p通信 公証⼈ (Notary) リモート認証 電⼦認証局 ・電⼦契約 ・EDI ・⾃動決済 Etc… 【分散台帳を拡張】 ブロックチェーンによる 取引の整合性を保証 B社DB

Slide 7

Slide 7 text

෼ࢄ୆ாʢϒϩοΫνΣʔϯʣܕαʔϏε • BtoBͷऔҾج൫ • औҾࢀՃاۀɹ1ࣾ͝ͱʹ1ϊʔυʢαʔόʔʣཱ͕ͭ • औҾͷ࣮ࡏੑɾඇվ͟Μੑ͸Notaryʢެূਓʣϊʔυ͕อূ • औҾ͝ͱʹೝఆೝূہͷλΠϜελϯϓΛԡ͢ • ʢকདྷతʹ͸ʣւ֎ʹݱ஍๏نʹج͍ͮͯϊʔυΫϥελΛߏஙՄೳ

Slide 8

Slide 8 text

Ϳͪ͋ͨͬͨ໰୊఺ • ஗͍ • ෳࡶ • ϊʔυ͕ΊͬͪΌ͍ͬͺཱ͍ͭʢ؅ཧ͸ʁʣ • ϢʔβʔೝՄɾೝূػೳ • 1ࣾ1αʔόʔͰ౷ҰతͳUIΛͲ͏ఏڙ͢Δͷ͔ʁ

Slide 9

Slide 9 text

໰୊఺ɿ஗͍ • Ethereum → 1τϥϯβΫγϣϯɹ15ʙ30ඵ • Corda → 15~6300TPS Corda͘͢͝ૣ͍ʂʂʁ PostgresϕϯνϚʔΫ σʔλετΞͱͯ͠ྫྷ੩ʹߟ͑Δͱ ΊͬͪΌ஗͍

Slide 10

Slide 10 text

໰୊఺ɿෳࡶ A社DB 統⼀認証基盤 A社 B社 分散台帳基盤 p2p通信 公証⼈ (Notary) リモート認証 電⼦認証局 ・電⼦契約 ・EDI ・⾃動決済 Etc… 【分散台帳を拡張】 ブロックチェーンによる 取引の整合性を保証 B社DB ϒϩοΫνΣʔϯΛ࢖ͬͨγεςϜ ී௨ͷγεςϜ サービス事業者 データベース A社 B社 Ұ໨ྎવ

Slide 11

Slide 11 text

໰୊఺ɿϊʔυͷ؅ཧ • ෼ࢄ୆ாʹ1ڌ఺1DBɾ1αʔόʔ $PSEB/PEF "SUFNJT .24FSWFS 4QSJOH4FSWFS RPC 0SBDMF 0S 1PTUHSFT 0Sʜ Corda ϊʔυߏ੒ ͜Ε͕औҾڌ఺͝ͱʹඞཁɻ ʢϊʔυͱ͔ʣ ݁࿦ɿKubernetesͰͲ͏ʹ͔͠·ͨ͠ɻ ʢৄࡉ͸·ͨͲ͔͜Ͱʣ

Slide 12

Slide 12 text

໰୊఺ɾɾɾɾɾ • ೝূɾೝՄ • ΩϡʔΠϯά • GUIͷఏڙ • Cordaϊʔυࣗମͷ؅ཧɻɻɻɻetc $PSEBͷ͓ੈ࿩Λ͢Δ୭͔͕ඞཁ

Slide 13

Slide 13 text

ΞʔΩςΫνϟߏ੒ $PSEB/PEF "SUFNJT 4QSJOH RP 0SBDMF 0S …… 3BJMT"1*4FSWFS 3FBDU4JOHMF1BHF"QQMJDBUJPO $PHOJUP "1*(BUFXBZ औҾσʔλ͸࣋ͨͳ͍ɻ ΩϡʔΠϯάɺόϦσʔγϣ ϯɺσʔλՃ޻౳Λ୲౰ ϩʔϧϕʔεೝՄʢ1VOEJUʣ ೝূɺ Ϣʔβʔϓʔϧ $PSEB-FEHFSͰऔҾ࣮ߦ औҾσʔλ͸શ֤ͯڌ఺ ϊʔυ͕ಠཱͯ͠อ࣋ ,VCFSOFUFT ϊʔυ؅ཧ ಠࣗΦϖϨʔλʔ ʢ؅ཧը໘Λ3BJMT͕ఏڙʣ

Slide 14

Slide 14 text

RailsΛબఆͨ͠ཧ༝ • PoC͔Β։ൃ։࢝ͨ͠ͷͰɺૉૣ͘։ൃͯ͠ૉૣ͘มߋͰ͖Δඞཁ͕ ͋ͬͨɻ • ͜ΕҎ্ϚΠΫϩαʔϏεʹ෼ׂ͢Δͱ։ൃνʔϜͷ਎͕࣋ͨͳ͍ɻ • ׳Ε͍ͯΔͷͰ։ൃεϐʔυ͕ग़Δɻ • REST͕͍ͪ͹Μɻ

Slide 15

Slide 15 text

Cordaͱͷ࿈ܞ • Corda ModelΛ࡞੒ͯ͠Rails WayͬΆ͘ • CordaଆͷSpring Server͔ΒJSONΛऔಘͯ͠RESTͰฦ͢ • Springଆ΋RESTͰߏ੒ΛͦΖ͓͑ͯ͘

Slide 16

Slide 16 text

Controller͸͜Μͳ෩ʹॻ͚Δ module Api class V1::CordaController < V1Controller # rubocop:disable Metrics/ClassLength def index @contracts = Corda::Contract[current_pod_name, current_org].all(**pagination_params, **search_params) end def show @contract = Corda::Contract[current_pod_name, current_org].find(params[:id]) @contract.cache_and_set_public_urls(current_org, request.base_url) contract = Contract.find_by(client_contract_id: @contract.client_contract_id) if contract.present? contract.corda_contract_id = @contract.corda_id contract.save! else Rails.logger.warn "corda record not found for client_contract_id:#{@contract.client_contract_id}" end end def create CreatePropose.call(contract_params, current_org, user_info) head :no_content end …….

Slide 17

Slide 17 text

ModelɿBase module CordaRecord module FinderMethods extend ActiveSupport::Concern module ClassMethods def new_from_corda_params(params) new(find_mapping(params)) end def find_mapping(*) raise NotImplementedError end def find(id) response = corda_client.get "#{api_name}/#{id}" new_from_corda_params(JSON.parse(response.body)) rescue Faraday::ResourceNotFound raise Errors::RecordNotFound, "Cannot find #{name}" end def find_by(attributes) body = find_response(attributes) return nil if body.empty? new_from_corda_params(body.first) rescue Faraday::ResourceNotFound nil end …….. private def find_response(attributes) response = corda_client.get "#{api_name}/" do |req| req.params = attributes.stringify_keys.transform_keys { |key| key.camelize(:lower) }.symbolize_keys end JSON.parse(response.body) end end end end module Corda class ContractBase < CordaRecord::Base # rubocop:disable Metrics/ClassLength include CordaRecord::FinderMethods attribute :corda_id, :string attribute :client_transaction_id, :string attribute :title, :string ……. def self.find_mapping(json) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize normalize_json(json) proposer = proposer_json(json) proposee = proposee_json(json) { corda_id: json['linerId'], client_contract_id: json['guestContractId'], title.... } end def self.proposer_json(json) proposer = parse_jsons_and_merge(json['proposerCompanyInfo'], json['proposerDepartmentInfo']) user_infos = json['userInfo'].deep_symbolize_keys proposer.merge(userInfo: user_infos[:proposer]) end ……. end end

Slide 18

Slide 18 text

Modelɿར༻ଆ module Corda class Propose < CordaRecord::Base include CordaRecord::CreateMethods include AwsSdkMethods attribute :id, :string attribute :title, :string validates :title, presence: true, length: { maximum: 60 } def self.api_name @api_name ||= "contracts/#{name.demodulize.downcase.underscore}" end def document_type=(document_type) # ఆٛ֎ͷ஋͕͖ͨ৔߹͸nil͕ઃఆ͞ΕɺpresenceͷνΣοΫͰΤϥʔʹ͢Δ self[:document_type] = DOCUMENT_TYPE_MAPPING[document_type] end end end

Slide 19

Slide 19 text

Railsʹ͓ੈ࿩Λ·͔ͤͯΑ͔ͬͨ͜ͱ • ॊೈʹ͍Ζ͍ΖٵऩͰ͖Δ • ࠔͬͨ͜ͱ͸Railsʹ·͔ͤΖ • Request SpecͰCordaͱͷ࿈ܞ·ͰΧόʔͰ͖ͨ

Slide 20

Slide 20 text

͔ۤͬͨ͜͠ͱ • ؾΛ͚ͭͳ͍ͱ͙͢ίʔυ͕ΧΦεʹͳΔ • ܕ͕ͳ͍ͷͰ౷੍͕औΕͳ͍ͱෆຬ͕ग़ͨ • ςετͱGatewayͷ྆ํΛ΍ΔͷͰRailsνʔϜʹෛՙ͕ूதͨ͠ • ͪΐͬͱͨ͜͠ͱΛ΍Ζ͏ͱ͢Δ͚ͩͰ໓஡ۤ஡େมʢ͜Ε͸Railsͷ ͍ͤͰ͸ͳ͍ʣ

Slide 21

Slide 21 text

~Leonardo da Vinci~ “୯७Ͱ͋Δ͜ͱ͸ɺڀۃͷચ࿅Ͱ͋Δ” 21

Slide 22

Slide 22 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ