Bitcoin CoreとRails Webアプリ開発ハンズオン

Bitcoin CoreとRails Webアプリ開発ハンズオン

日本暗号通貨ユーザ会 ビットコインとか勉強会 第37回にて、

Bitcoin CoreのRPC APIをRuby on Railsから操作する簡単なWebアプリ開発ハンズオンを行いました。

https://cryptocurrency.connpass.com/event/161743/

D3e027f453bb96ac1398cc98620f2920?s=128

Shu Kobuchi

January 31, 2020
Tweet

Transcript

  1. ϏοτίΠϯͱ͔ษڧձ #JUDPJO$PSFͱ3VCZPO3BJMTͰ 8FCΞϓϦΛ։ൃ͢ΔϋϯζΦϯ ೥݄೔!)BTI)VC ೔ຊ҉߸௨՟Ϣʔβձɹখᔹप 4IV,PCVDIJ

  2. ࣗݾ঺հ খᔹपɹ4IV,PCVDIJɹ!TIV@LPCTIVLPCVDIJ ෱Ԭݝ൧௩ࢢੜ·Εɹฌݿݝ੢ٶࢢɾๅ௩ࢢҭͪ ਆށେֶւࣄՊֶ෦ଔۀ ಸྑઌ୺Պֶٕज़େֶӃେֶ৘ใՊֶݚڀՊम࢜ྃ ৽ଔͰՈిϝʔΧʔͰιϑτ΢ΣΞ։ൃ ͦͷޙ4*FSͰͷडୗ։ൃ౳ લ൒େࡕͷϕϯνϟʔͰ#JUDPJO8FC8BMMFUࢼ࡞඼։ൃ ʙ*5ϕϯμʔͷେࡕࢧࣾʹೖࣾ͠4& ʙϒϩοΫνΣʔϯͷاը౳ਪਐͷͨΊ౦ژຊࣾసۈ

    ʙϑϨηοπͷγχΞιϑτ΢ΣΞΤϯδχΞ w Ծ૝௨՟ࣄۀऀ޲͚΢ΥϨοτ։ൃͷޙɺݱࡏ͸อकɾӡ༻Λ୲౰ 2
  3. ίϛϡχςΟ঺հ ೔ຊ҉߸௨՟ϢʔβձɹIUUQTDSZQUPDVSSFODZDPOOQBTTDPN  ۚ  ౔ 04$ ΦʔϓϯιʔεΧϯϑΝϨϯε ౦ژ ʮϏοτίΠϯͱ͔ษڧձʯʢ݄̍ճɿฏ೔໷ʣ

    w ࣍ճ͸೥݄೔ ໦ ͰʮϞφίΠϯͱ͔ษڧձʯௐ੔த ʮ҉߸௨՟ಡॻձʯʢ݄̍ճɿฏ೔໷ʣ w ࣍ճ͸೥݄೔ Ր ʮ"CBMBODIFʯ DSBTIBDBEFNZ *5ܥಈը഑৴ ʹͯϏοτίΠϯͱ͔ษڧձͷΞʔΧΠϒ഑৴த
 IUUQTDSBTIBDBEFNZDPNNVOJUZDSZQUPDVSSFODZ :PV5VCFνϟϯωϧʢษڧձʗಡॻձʣIUUQCJUMZZPVUVCFDDTUVEZ 3
  4. ٕज़ॻయ  ౔  ೔ ٕज़ॻయͰϒϩοΫνΣʔϯ߹ಉࢽΛൢച IUUQCJUMZCDKPJOU دߘऀืूத "༻ࢴʙϖʔδఔ౓ 

    ೔ ݪߘకΊ੾Γ ˞ࠓճͷษڧձͷ಺༰΋هࡌ༧ఆ 4
  5. #JUDPJO-BZFSΠϕϯτ  ໦ $SZQUP(BSBHF #MPDLTUSFBN͕)BTI)VCͰΠϕϯτ #JUDPJO-BZFSςΫϊϩδʔͷݱঢ়ͱൃలͷల๬ IUUQTIBTIIVCDPOOQBTTDPNFWFOU 5

  6. (#&$ (P#MPDLDIBJO&OHJOFFSJOH$PNNVOJUZ IUUQTHPCMPDLDIBJOOFUXPSL ίʔυΛॻ͘͜ͱ͚͕ͩ#MPDLDIBJOΛਐԽͤ͞Δ ʮಈըͰֶͿϒϩοΫνΣʔϯʯͳͲίϯςϯπ๛෋ ݄ʹΠϕϯτ#JUDPJOΠϕϯτاըத 6

  7. ϏοτίΠϯ͸Φʔϓϯιʔε ϏοτίΠϯ #JUDPJO ͸Φʔϓϯιʔε ୭Ͱ΋։ൃʹࢀՃՄೳʂ
 IUUQTHJUIVCDPNCJUDPJOCJUDPJO ϏοτίΠϯΛ͸͡Ίɺ҉߸௨՟ɾϒϩοΫνΣʔϯͷଟ͘͸044 ٕज़తʹ΋໘ന͍ʂʂ ϥΠτίΠϯ -JUFDPJO

    ͸#JUDPJOͷιʔείʔυ͔ΒϑΥʔΫ
 IUUQTHJUIVCDPNMJUFDPJOQSPKFDUMJUFDPJO ϞφίΠϯ .POBDPJO ͸-JUFDPJOͷιʔείʔυ͕ϕʔε
 IUUQTHJUIVCDPNNPOBDPJOQSPKFDUNPOBDPJO ΠʔαϦΞϜ &UIFSFVN ΋Φʔϓϯιʔε
 IUUQTHJUIVCDPNFUIFSFVNHPFUIFSFVN 7
  8. ΞδΣϯμ #JUDPJO$PSFͷΠϯετʔϧ %PDLFSͰ3VCZͱ3BJMT؀ڥͷΠϯετʔϧ #JUDPJO$PSF 3BJMTͰ8FCΞϓϦέʔγϣϯ։ൃ ͓அΓɿ ࠓճͷσϞͰ࢖͏ΞϓϦέʔγϣϯ͸։ൃΛମݧ͍ͨͩ͘؆қతͳ΋ͷͰ͢ ͷͰɺެ։ͯ͠ͷ͝ར༻͸͓߇͍͑ͩ͘͞ 8

  9. CJUDPJOSC CJUDPJOSVCZ IUUQTHJUIVCDPNMJBOCJUDPJOSVCZ CJUDPJOͷSVCZϥΠϒϥϦɺ#JUDPJOE CJUDPJODPSF ͱซ༻ ్த͔ΒDIBJOUPQF$50҆౔ໜږࢯ͕DPOUSJCVUFSʹ CJUDPJOSVCZͷ-JBO͕؅ཧΛ΍ΊͨͷͰɺ҆౔ࢯ͕৽ͨʹCJUDPJOSCΛΦʔϓ ϯιʔεͰ։ൃ։࢝ IUUQTHJUIVCDPNDIBJOUPQFCJUDPJOSC

    ॻ੶͸CJUDPJOSVCZͰॻ͔Ε͍ͯΔ͕ɺҰ෦͸CJUDPJOSCͰͷίʔσΟϯάʹ ΋Ԡ༻Մೳ 9
  10. 3VCZPO3BJMTΦεεϝॻ੶ ࠇా౒ஶʮ3VCZPO3BJMT࣮ફΨΠυʯ JNQSFTTUPQHFBSγϦʔζ  ࢴͷଞɺ,JOEMF൛͋Γ 10

  11. 8JOEPXTͷํͷࣄલ४උ 8JOEPXTͷํ͸6CVOUVΛΠϯετʔϧ͍ͯͩ͘͠͞ IUUQTXXXNJDSPTPGUDPNKBKQQVCVOUV OCMHHINTW BDUJWFUBCQJWPUPWFSWJFXUBC ࢀߟɿ IUUQTRJJUBDPNXIJNJUFNTGECCEEBGCB ͔͜͜Βઌɺ8JOEPXTϢʔβͷํ͸6CVOUVʹϩάΠϯͯ͠ߦ͍ͬͯͩ͘͞ 11

  12. .BDʹCJUDPJOEΠϯετʔϧ IUUQTCJUDPJOPSHKBEPXOMPBE Ͱ.BD༻#JUDPJO$PSFͷUBSH[Λμ΢ϯϩʔυɺΠϯετʔϧ DE XHFUIUUQTCJUDPJOPSHCJOCJUDPJODPSFCJUDPJO PTYUBSH[ UBS[YWGCJUDPJOPTYUBSH[ DECJUDPJOCJO TVEPDQ VTSMPDBMCJO

    12
  13. 6CVOUVʹCJUDPJOEΠϯετʔϧ DE XHFUIUUQTCJUDPJOPSHCJOCJUDPJODPSFCJUDPJO Y@MJOVYHOVUBSH[ UBS[YWGCJUDPJOY@MJOVYHOVUBSH[ DECJUDPJOCJO TVEPDQ VTSMPDBMCJO 13

  14. ॳظىಈͱऴྃ ىಈ CJUDPJOESFHUFTUUYJOEFYEBFNPO ϒϩοΫνΣʔϯ৘ใΛࢀর CJUDPJODMJSFHUFTUHFUCMPDLDIBJOJOGP ఀࢭ CJUDPJODMJSFHUFTUTUPQ ੨ࣈ͸λʔϛφϧʹଧͪࠐΜͰ࣮ߦ͢ΔίϚϯυ طʹΠϯετʔϧͯ͠Ҏલ࣮ߦͨ͜͠ͱ͋Δํ͸͜ͷϖʔδ͸ඈ͹ͯͩ͘͠͞ ͍

    14
  15. CJUDPJODPOG -JOVYͷ৔߹ DEdCJUDPJO .BDͷ৔߹ DE6TFST\64&3^-JCSBSZ"QQMJDBUJPO4VQQPSU#JUDPJO OBOPCJUDPJODPOG·ͨ͸WJCJUDPJODPOG ԼهΛίϐϖͯ͠อଘ 15 regtest=1 txindex=1

    server=1 daemon=1 rpcuser=hoge rpcpassword=hoge [regtest] rpcport=18443 port=18444 regtest=1 # regtestϞʔυ༗ޮԽ txindex=1 # શͯͷTXΛऔಘ(ϑϧϊʔυ) server=1 # RPCΞΫηεՄೳʹ daemon=1 # ίϯιʔϧϩά͕ग़ͳ͍ rpcuser=hoge # RPCΞΫηεϢʔβ rpcpassword=hoge # RPCΞΫηεύεϫʔυ [regtest] # regtest༻ઃఆ rpcport=18443 # RPC༻port port=18444 # ଞͷϊʔυͱ௨৴͢Δport
  16. ࠶౓CJUDPJOΛىಈ ىಈ CJUDPJOE ϒϩοΫνΣʔϯ৘ใΛࢀর CJUDPJODMJHFUCMPDLDIBJOJOGP ىಈͨ͠··ʹ͓ͯ͘͠ 16

  17. %PDLFSΞΧ΢ϯτ࡞੒ %PDLFSͷΞΧ΢ϯτͳ͍ํ͸ԼهͰ࡞੒ IUUQTIVCEPDLFSDPNTJHOVQ 17

  18. .BDͰ3BJMT؀ڥͷೖͬͨ%PDLFSΠϯετʔϧ IUUQTIVCEPDLFSDPNFEJUJPOTDPNNVOJUZEPDLFSDFEFTLUPQNBD ʮ(FU%PDLFSʯϘλϯΛԡԼ μ΢ϯϩʔυͨ͠%PDLFSENHΛμϒϧΫϦοΫ %PDLFSͷΞΠίϯΛ"QQMJDBUJPOϑΥϧμʹυϥοάυϩοϓ 'JOEFSͷʮΞϓϦέʔγϣϯʯϑΥϧμʹ͋Δ%PDLFSΞΠίϯΛμϒϧΫ ϦοΫͯ͠ىಈ λʔϛφϧͰ7FS֬ೝʢ੨ࣈ͸λʔϛφϧͰ࣮ߦ͢ΔίϚϯυʣ EPDLFSWFSTJPO EPDLFSDPNQPTFWFSTJPO

    18
  19. (JUͷΠϯετʔϧ HJUWFSTJPO HJUWFSTJPO "QQMF(JU ͷΑ͏ʹWFSTJPO͕ग़Ε͹ೖ͍ͬͯΔ (JUͷೖ͍ͬͯͳ͍ํ͸Πϯετʔϧ .BDͷ৔߹ IUUQTHJUTDNDPNEPXOMPBENBD 6CVOUVͷ৔߹ TVEPBEEBQUSFQPTJUPSZQQBHJUDPSFQQB

    TVEPBQUHFUVQEBUF TVEPBQUHFUJOTUBMMHJU 19
  20. 6CVOUV΁ͷ%PDLFSͷΠϯετʔϧ IUUQTEPDTEPDLFSDPNJOTUBMMMJOVYEPDLFSDFVCVOUV ʹԊͬͯΠϯετʔϧ TVEPBQUHFUVQEBUF ԼهߦΛίϐϖ࣮ͯ͠ߦ 1%'͔Βίϐϖ͢Δͱվߦ͕ೖͬͯ͠·͏͔΋  TVEPBQUHFUJOTUBMMBQUUSBOTQPSUIUUQTDBDFSUJpDBUFTDVSMHOVQH BHFOUTPGUXBSFQSPQFSUJFTDPNNPO ԼهߦΛίϐϖ࣮ͯ͠ߦ

    DVSMGT4-IUUQTEPXOMPBEEPDLFSDPNMJOVYVCVOUVHQHcTVEP BQULFZBEE ԼهߦΛίϐϖ࣮ͯ͠ߦ TVEPBEEBQUSFQPTJUPSZEFC<BSDIBNE>IUUQT EPXOMPBEEPDLFSDPNMJOVYVCVOUV MTC@SFMFBTFDT TUBCMF 20
  21. 6CVOUVʹ%PDLFSΠϯετʔϧଓ͖ TVEPBQUHFUVQEBUF TVEPBQUHFUJOTUBMMEPDLFSDFEPDLFSDFDMJDPOUBJOFSEJP TVEPBQUHFUJOTUBMMEPDLFSDPNQPTF TVEPVTFSNPEB(EPDLFS XIPBNJ  7FS֬ೝ EPDLFSWFSTJPO EPDLFSDPNQPTFWFSTJPO

    21
  22. %PDLFSͰ3BJMT؀ڥͷߏங 8JOEPXEͷํ͸6CVOUVͱͷڞ༗ϑΥϧμʹDEίϚϯυͰҠಈ HJUDMPOFIUUQTHJUIVCDPNPJBYSBJMTDPNQPTFHJU DESBJMTDPNQPTF TFUVQTI 6CVOUVʹͯݖݶ໰୊Ͱ࣮ߦͰ͖ͳ͚Ε͹ԼهΛࢀর IUUQTRJJUBDPNOBPNJDIJZJUFNTBBBFDD ىಈ EPDLFSDPNQPTFVQE ఀࢭ

    EPDLFSDPNQPTFTUPQ 22
  23. 3BJMTΞϓϦέʔγϣϯͷ࡞੒ %PDLFSΛఀࢭ͍ͤͯ͞Δ৔߹͸ɺ࠶౓ىಈ EPDLFSDPNQPTFVQE EPDLFSDPNQPTFFYFDXFCCBTI ͔͜͜Β͸EPDLFS಺ͰίϚϯυ࣮ߦ SBJMTWFSTJPO 3BJMTܥ͕ೖ͍ͬͯΕ͹0, ϩάΞ΢τ͢ΔͳΒԼهͷίϚϯυ FYJU ࠶౓ίϯςφʹϩάΠϯ

    EPDLFSDPNQPTFFYFDXFCCBTI 23
  24. ΞϓϦΛ։ൃ EPDLFS಺ͰίϚϯυ࣮ߦ SBJMTOFXCJUDPJOUPLBEQPTUHSFTRMTLJQUFTUVOJU 7JTVBM4UVEJP$PEFͳͲίʔυΤσΟλΛ։͘ʢ׳Ε͍ͯΔ΋ͷͰ0,ʣ ͳ͍৔߹͸74$PEFΛΠϯετʔϧ IUUQTB[VSFNJDSPTPGUDPNKBKQQSPEVDUTWJTVBMTUVEJPDPEF (FNpMFߦ໨ͷԼ͋ͨΓʹԼهΛ௥Ճ DECJUDPJOUPLB CVOEMF ԼهͷΑ͏ʹग़Ε͹0,

    24 gem 'bitcoinrb', require: 'bitcoin' Bundle complete! 18 Gemfile dependencies, 98 gems now installed. Bundled gems are installed into `/usr/local/bundle`
  25. +BWB4DSJQUͱ%# ZBSO DPOpHEBUBCBTFZNM ͷԼʹԼهΛ௥ه ۭͷ%#ͷ࡞੒ SBJMTECDSFBUF 25 default: &default adapter:

    postgresql encoding: unicode # For details on connection pooling, see Rails configuration guide # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> host: db username: postgres password: ""
  26. )PTUT౳ͷઃఆ )PTUTͷฤू .BDͷ৔߹ TVEPOBOPQSJWBUFFUDIPTUT 6CVOUVͷ৔߹ TVEPOBOPFUDIPTUT ԼهΛ৽͍͠ߦͰ௥Ճʢݩʑ͋ΔzMPDBMIPTUz͸ফ͞ͳ͍ɺ͜͜ʹ௥ه͠ͳ ͍  DPOpHJOJUJBMJ[FSTσΟϨΫτϦʹɺʮCMPDLFE@IPTUTSCʯͱ͍͏ϑΝΠϧΛ৽ن࡞੒

    ԼهΛίϐϖ 26 CJUDPJOUPLBDPN Rails.application.configure do config.hosts << "bitcointoka.com" end
  27. XFCDPOTPMFͷઃఆ DPOpHFOWJSPONFOUTEFWFMPQNFOUSCʹ௥Ճ ݩʑ͋Δߦ໨ ͷԼʹԼهΛ௥Ճ 27 config.file_watcher = ActiveSupport::EventedFileUpdateChecker config.web_console.whitelisted_ips =

    [ "172.16.0.0/12" ]
  28. 3BJMTͷىಈ SBJMTTC ϒϥ΢βͰΞΫηε IUUQCJUDPJOUPLBDPN 28

  29. ίϯτϩʔϥΛ௥Ճ $USM DͰ3BJMTఀࢭ ίϯτϩʔϥΛ௥Ճ SBJMTHDPOUSPMMFSCJUDPJO@BQQ CJUDPJOUPLBBQQDPOUSPMMFSTCJUDPJO@BQQ@DPOUSPMMFSSC ͳͲ͕࡞੒͞Ε͍ͯͯɺ͜ͷϑΝΠϧΛฤू ߦͷؒʹԼهΛ௥Ճɺߦͷ্ʹࠨهΛ௥ه 29 class

    BitcoinAppController < ApplicationController end require 'bitcoin' require 'net/http' require 'json' Bitcoin.chain_params = :regtest RPCUSER="hoge" RPCPASSWORD="hoge" HOST="host.docker.internal" PORT=18443 def explorer @blockchaininfo = bitcoinRPC('getblockchaininfo',[]) logger.debug @blockchaininfo render template: 'bitcoin_app/explorer' end private def bitcoinRPC(method,param) http = Net::HTTP.new(HOST, PORT) request = Net::HTTP::Post.new('/') request.basic_auth(RPCUSER,RPCPASSWORD) request.content_type = 'application/json' request.body = {method: method, params: param, id: 'jsonrpc'}.to_json JSON.parse(http.request(request).body)["result"] end
  30. ը໘ͱϧʔςΟϯάΛ௥Ճ BQQWJFXTCJUDPJO@BQQʹϑΝΠϧʮFYQMPSFSIUNMFSCʯΛ৽ن࡞੒ɻ ԼهΛίϐϖ طଘͷDPOpHSPVUFTSCʹ ߦͷؒʹHFU͔Β࢝·ΔߦΛ௥Ճ SBJMTTC IUUQCJUDPJOUPLBDPNFYQMPSFS KTPO͕ը໘ʹө͠ग़͞ΕΔ 30 <td><%=

    @blockchaininfo %></td><br> Rails.application.routes.draw do get '/explorer', to: 'bitcoin_app#explorer' end
  31. #JUDPJO3BJMTΞϓϦ։ൃଓ͖ (JU)VC্ʹ͋Δ3BJMTΞϓϦΛࢀߟʹਐΊ͍͖ͯ·͢ IUUQTHJUIVCDPNTIVLPCSBJMTCJUDPJO FYQMPSFSίϯτϩʔϥΛ࡞ͬͨΈ͍ͨʹɺ֤ػೳΛ௥Ճ͍͖ͯ͠·͠ΐ͏ʂ 31 3FTU7FSC 63* "DUJPO ϝιου 1SFpY

    ΤΠϦΞε ϚΠχϯά HFU NJOJOH NJOJOH  ϒϩοΫͷ ৘ใ HFU CMPDLJE CMPDLJOGP CMPDLJOGP ૹۚೖྗ TFOEJOHT TFOEJOHT TFOEJOHT ૹۚॲཧ QPTU TFOU TFOU
  32. ίϛϡχςΟ঺հ ೔ຊ҉߸௨՟ϢʔβձɹIUUQTDSZQUPDVSSFODZDPOOQBTTDPN ʮϏοτίΠϯͱ͔ษڧձʯʢ݄̍ճɿฏ೔໷ʣ w ࣍ճ͸೥݄೔ ໦ ͰʮϞφίΠϯͱ͔ษڧձʯௐ੔த ʮ҉߸௨՟ಡॻձʯʢ݄̍ճɿฏ೔໷ʣ w ࣍ճ͸೥݄೔

    Ր ʮ"CBMBODIFʯ DSBTIBDBEFNZ *5ܥಈը഑৴ ʹͯϏοτίΠϯͱ͔ษڧձͷΞʔΧΠϒ഑৴த
 IUUQTDSBTIBDBEFNZDPNNVOJUZDSZQUPDVSSFODZ :PV5VCFνϟϯωϧʢษڧձʗಡॻձʣIUUQCJUMZZPVUVCFDDTUVEZ 32
  33. ࢀߟࢿྉ

  34. .BDʹ3VCZΛΠϯετʔϧ IUUQTXXXPJBYKQSBJMT[BLLBOSBJMT@@@JOTUBMMBUJPO@PO@NBDPTYIUNM ͷSVCZ7FSΛʹஔ͖׵͑3BJMTͷ7FSΛʹஔ͖׵͑ TVEPQPSUVOJOTUBMMSVCZ SWNJNQMPEF CSFXMJOLBVUPDPOG CSFXVOMJOLBVUPDPOGCSFXMJOLBVUPDPOG CSFXJOTUBMMSCFOWSVCZCVJME CSFXVQEBUFCSFXVQHSBEFSVCZCVJME SCFOWJOTUBMM

    ͔ͳΓ͔͔࣌ؒΔ SCFOWHMPCBM SVCZW SVCZQ SFWJTJPO <Y@EBSXJO> 34
  35. .BDʹ3BJMTΛΠϯετʔϧ DE OBOPHFNSD ԼهΛίϐϖ $USM PͰॻ͖ࠐΈ $USM YͰด͡Δ HFNJOTUBMMCVOEMFS CVOEMFW

    HFNJOTUBMMSBJMTWFSTJPOdz SBJMTW 3BJMT 35 install: --no-ri --no-rdoc update: --no-ri --no-rdoc
  36. .BDͰ3BJMTΛىಈ HJUDMPOFIUUQTHJUIVCDPNTIVLPCSBJMTCJUDPJO DESBJMTCJUDPJO CVOEMFJOTUBMM CSFXJOTUBMMZBSO SBJMTT 1MFBTFSVOAZBSOJOTUBMMDIFDLpMFTAUPVQEBUFͳͷͰԼهΛ࣮ߦ ZBSOJOTUBMMDIFDLpMFT IUUQMPDBMIPTU 36

  37. SBJMTCJUDPJOΛૢ࡞ IUUQMPDBMIPTUFYQMPSFS 37

  38. 7JSUVBM#PY 7BHSBOUͰ6CVOUV 7JSUVBM#PYΛΠϯετʔϧ IUUQTXXXWJSUVBMCPYPSH WBHSBOUΛΠϯετʔϧ IUUQTXXXWBHSBOUVQDPN 38

  39. 7BHSBOU6CVOUVͰ3BJMTΛಈ͔͢ NLEJSWBHSBOU DEWBHSBOU CFOUPVCVOUVͰॳظԽ WBHSBOUJOJUCFOUPVCVOUV ॳΊͯɿॳظઃఆɹճ໨Ҏ߱ɿىಈ WBHSBOUVQ TTI઀ଓ WBHSBOUTTI 39

  40. 6CVOUVʹ3VCZͱ3BJMTΛΠϯετʔϧ IUUQTXXXPJBYKQSBJMT[BLLBOSBJMT@@@JOTUBMMBUJPO@PO@VCVOUIUNM TVEPBQUHFUVQEBUF TVEPBQUHFUZJOTUBMMHJUDVSMH NBLF TVEPBQUHFUZJOTUBMM[MJCHEFWMJCTTMEFWMJCSFBEMJOFEFW TVEPBQUHFUZJOTUBMMMJCZBNMEFWMJCYNMEFWMJCYTMUEFW TVEPBQUHFUZJOTUBMMTRMJUFMJCTRMJUFEFWOPEFKT SWNJNQMPEF CBTISWNDPNNBOEOPUGPVOEͱग़ͯ0,

    DE HJUDMPOFHJUHJUIVCDPNTTUFQIFOTPOSCFOWHJUSCFOW FDIPFYQPSU1"5))0.&SCFOWCJO1"5)dCBTISD FDIPFWBM SCFOWJOJU dCBTISD FYFD4)&-- 40
  41. 6CVOUVʹ3VCZΛΠϯετʔϧ NLEJSQdSCFOWQMVHJOT DEdSCFOWQMVHJOT HJUDMPOFHJUHJUIVCDPNTTUFQIFOTPOSVCZCVJMEHJU SCFOWJOTUBMM ͔ͳΓ͔͔࣌ؒΔ SCFOWHMPCBM SCFOWWFSTJPO Ͱ͋Δ͜ͱ XIJDISVCZ

    ྫ IPNFWBHSBOUSCFOWTIJNTSVCZ SVCZW Ͱ͋Δ͜ͱ 41
  42. 6CVOUVʹ3BJMTΛΠϯετʔϧ DE OBOPHFNSD ԼهΛίϐϖ $USM PͰॻ͖ࠐΈ $USM YͰด͡Δ HFNJOTUBMMSBJMTWFSTJPOdz SCFOWSFIBTI

    SBJMTW 3BJMT 42 install: --no-ri --no-rdoc update: --no-ri --no-rdoc
  43. 6CVOUVͰ3BJMTΛىಈ DEWBHSBOU HJUDMPOFIUUQTHJUIVCDPNTIVLPCSBJMTCJUDPJO DESBJMTCJUDPJO CVOEMFJOTUBMM SBJMTT 1MFBTFSVOAZBSOJOTUBMMDIFDLpMFTAUPVQEBUFͳͷͰԼهΛ࣮ߦ ZBSOJOTUBMMDIFDLpMFT CBTIZBSODPNNBOEOPUGPVOE TVEPBQUHFUJOTUBMMZBSO

    !SBJMTXFCQBDLFS!5IFFOHJOFOPEFJTJODPNQBUJCMFXJUI UIJTNPEVMF&YQFDUFEWFSTJPO(PUl TVEPBQUHFUJOTUBMMOQN TVEPOQNJOTUBMMHO 43
  44. 3BJMTىಈ FYJU WBHSBOUఀࢭ WBHSBOUIBMU OBOP7BHSBOUpMF DPOpHWNOFUXPSLQSJWBUF@OFUXPSL JQlz
 ͷίϝϯτΞ΢τ  Λ֎͢

    WBHSBOUVQ WBHSBOUTTI DEWBHSBOUSBJMTCJUDPJO ZBSOJOTUBMMDIFDLpMFT SBJMTTC IUUQ 44
  45. 8JOEPXTʹ3VCZͱ3BJMTΛΠϯετʔϧ IUUQTXXXPJBYKQSBJMT[BLLBOSBJMT@@@JOTUBMMBUJPO@PO@XJOEPXTIUNM 45

  46. DE NLEJSXPSL DEXPSL SBJMTOFXSBJMTCJUDPJOIBOETPO SBJMTHDPOUSPMMFSCJUDPJO@BQQ 46

  47. #JUDPJO$PSF #JUDPJOϦϑΝϨϯε࣮૷ͷϊʔυ ެࣜΫϥΠΞϯτιϑτ΢ΣΞ ։ൃݴޠ͸$  গ͠1ZUIPO΋ೖΔΑ͏ʹ CJUDPJOEͱ΋͍͏ 47

  48. ϏϧυͱΠϯετʔϧ HJUDMPOFIUUQTHJUIVCDPNCJUDPJOCJUDPJO DECJUDPJO HJUUBH &OUFS͔ˣΩʔͰWΛݟ͚ͭΔ HJUDIFDLPVUW 6CVOUV IUUQTRJJUBDPNLFBDIJUFNTCCDDFG w ʮϏϧυͷલʹґଘ͢ΔQBDLBHFΛΠϯετʔϧʯ͔Βॱ൪ʹ࣮ߦ

    .BD IUUQTCMPDLDIBJOKQCJUDPJOJOTUBMMCJUDPJOEPONBD NBLFʹ͕͔͔࣌ؒΔͷͰɺͦͷؒʹઆ໌ 48
  49. ࠶౓ىಈͯ͠ίϚϯυΛݟΔ CJUDPJOE CJUDPJODMJIFMQ CJUDPJODMJIFMQHFUCMPDLDIJBOJOGP 49

  50. 3FHUFTUϞʔυ 5FTUOFU͸ແՁ஋ͳ#JUDPJOͷྲྀ௨͢ΔωοτϫʔΫ 1P8 1SPPGPG8PSL ܕͰϚΠχϯά΋͍ͯ͠Δ w ϒϩοΫੜ੒ִؒฏۉ෼͕ͩɺ҆ఆ͠ͳ͍ w ٸܹʹૣ͘ͳͬͨ൓ಈͰ஗͘ͳͬͨΓ 3FHUFTU͸։ൃ༻ͷωοτϫʔΫ

    ೚ҙͷλΠϛϯάͰϚΠχϯά͠์୊ʢίετ̌ʣ w ঝೝͱ͍͏ςετ΋͙͢ʹͰ͖Δ ωοτͷͳ͍؀ڥͰ΋࢖͑Δ ෳ਺୆ܨ͛Δ͜ͱ΋Մೳ w 3FPSHͷςετ΋؆୯ʹͰ͖Δ w #MPDLXJUIIPMEJOHBUUBDL ηϧϑΟογϡɾϚΠχϯά߈ܸ ΋؆୯ 50
  51. 3FHUFTUϚΠχϯάͱૹۚ CJUDPJODMJHFUOFXBEESFTT .T'9D:#-CJW'R-VSR-%SC&K7 BEESFTT.T'9D:#-CJW'R-VSR-%SC&K7 ΑΓޙ͸֤ࣗग़ྗ͞ΕͨΞυϨεͰஔ͖׵͍͑ͯͩ͘͞ CJUDPJODMJHFOFSBUFUPBEESFTTBEESFTT CJUDPJODMJHFUCBMBODF CJUDPJODMJHFUOFXBEESFTT /"T6RK&5UX;E#$U"%UUFN-35JB2 BEESFTT/"T6RK&5UX;E#$U"%UUFN-35JB2

    ΑΓޙ͸֤ࣗग़ྗ͞ΕͨΞυϨεͰஔ͖׵͍͑ͯͩ͘͞ CJUDPJODMJTFOEUPBEESFTTBEESFTT DFFGFDEGEBDBCBDEFCDDE BEF 51
  52. τϥϯβΫγϣϯͷࢀর UYJEDFFGFDEGEBDBCBDEFCDD EBEF ΑΓޙ͸֤ࣗग़ྗ͞ΕͨτϥϯβΫγϣϯͰஔ͖׵͍͑ͯͩ͘͞ CJUDPJODMJHFUUSBOTBDUJPOUYJE CJUDPJODMJHFUSBXUSBOTBDUJPOUYJE SBXUSBOTBDUJPO CJUDPJODMJHFUSBXUSBOTBDUJPOUYJE  FDIPSBXUSBOTBDUJPO

    CJUDPJODMJEFDPEFSBXUSBOTBDUJPOSBXUSBOTBDUJPO 52
  53. ΞϦε͕Ϙϒʹ#5$ΛૹΔ Ҏલड͚औֹ͍ͬͯͨΛ߹ࢉͯ͠ɺ૬खʹૹΓɺ͓௼Γ͸ࣗ෼΁ 59தʹهࡌͷͳֹ͍ ͜͜Ͱ͸#5$ ͸ޙʹϚΠφʔ΁ τϥϯβΫγϣϯͷߏ଄ 53 ΞϦε Ϙϒ 5SBOTBDUJPO

    59 */165 065165 ΞϦε Ωϟϩϧ ΞϦεˠϘϒ #5$ ΩϟϩϧˠΞϦε #5$ ΞϦεˠΞϦε ͓௼Γ  #5$ #5$ σϏοτˠΞϦε #5$ #5$ σϏοτ ܭ#5$ ܭ#5$ ϚΠφʔ ωοτϫʔΫख਺ྉ #5$ ˞59ʹهࡌ͸ͳ͍ ൿີ伴Λࠩ͠ࠐΜͰ ϩοΫղআɿిࢠॺ໊ ΞϦεͷ ൿີ伴 ΞϦεͷ ൿີ伴 ΞϦεͷ ެ։伴 Ϙϒͷ ެ։伴 ΞϦεͷ ެ։伴 ΞϦεͷ ެ։伴
  54. 3FMFBTF/PUFͷ೔ຊޠ༁CZ҆౔ໜږࢯ IUUQTCJUDPJODPSFPSHKBSFMFBTFT #JUDPJO$PSFWFSTJPO 54 $ bitcoin-cli getbalances { "mine": {

    "trusted": 7699.99774240, "untrusted_pending": 0.00000000, "immature": 2500.00205560 } }
  55. 3VCZΠϯετʔϧ .BDͷ৔߹ IUUQTXXXPJBYKQSBJMT[BLLBO SBJMT@@@JOTUBMMBUJPO@PO@NBDPTYIUNM 6CVOUVͷ৔߹ IUUQTXXXPJBYKQSBJMT[BLLBO SBJMT@@@JOTUBMMBUJPO@PO@VCVOUIUNM 3VCZΠϯετʔϧ·ͰʢʮHFNSDͷ࡞੒ʯͷखલSVCZW·Ͱʣ 3BJMTΠϯετʔϧ͸ෆཁ ίʔυதͷWFS͸ʹஔ͖׵࣮͑ͯߦ

    55
  56. CJUDPJOSCΠϯετʔϧ IUUQTHJUIVCDPNDIBJOUPQFCJUDPJOSC 3&"%.&ΛಡΜͰΠϯετʔϧ 56

  57. JSC 3VCZର࿩ܕϞʔυ CJUDPJOSC JSC SFRVJSFCJUDPJO #JUDPJODIBJO@QBSBNTSFHUFTU #JUDPJO,FZHFOFSBUF #JUDPJO,FZHFOFSBUFQSJW@LFZ #JUDPJO,FZHFOFSBUFQVCLFZ 57

  58. .OFNPOJD #JUDPJO8BMMFU.BTUFS,FZHFOFSBUF 58 irb(main):035:0> mk = Bitcoin::Wallet::MasterKey.generate => #<Bitcoin::Wallet::MasterKey:0x00000000019d8d10 @mnemonic=["shed",

    "horror", "bleak", "destroy", "shield", "salute", "dose", "blast", "aim", "orphan", "crawl", "model", "salon", "fall", "amount", "repair", "unfold", "craft", "wall", "mean", "strong", "obtain", "holiday", "couple"], @seed="2a462344bbeafbc81996bd3bb93beb3eb0db9e1826de4dfab165e2d6714bf37f8a4ade6195579ae686365dd467e8687791 9bca0740f58eaa1beb393bb557471e", @encrypted=false, @salt=""> irb(main):036:0> mk = Bitcoin::Wallet::MasterKey.generate.mnemonic => ["rocket", "habit", "slam", "pioneer", "ethics", "client", "outer", "name", "alarm", "bulb", "visa", "special", "index", "shadow", "tube", "bronze", "focus", "skin", "deposit", "climb", "tattoo", "chimney", "anger", "daring"]
  59. #JUDPJO4DSJQU -*'0 -BTU*O'JSTU0VU ͷ୯७ͳεΫϦϓτ 'PSUIͷΑ͏ͳٯϙʔϥϯυه๏ #JUDPJO5SBOTBDUJPOʹ͸ඞؚͣ·ΕΔ #JUDPJO$PSF CJUDPJOE ΍ϥΠϒϥϦΛ࢖͏ͱɺ#JUDPJO4DSJQUΛҙࣝ͠ͳ ͯ͘΋ɺϓϩάϥϜ͸ॻ͚Δ

    6OMPDLJOH4DSJQUͱ-PDLJOH4DSJQUΛಉ࣌ʹ࣮ߦ ਖ਼࣮͘͠ߦͰ͖Ε͹6OMPDLJOH4DSJQUͰ-PDLJOH4DSJQUΛղআͯ͠ɺτϥϯ βΫγϣϯͷ༗ޮੑΛࣔͤΔ 59 6OMPDLJOH4DSJQU -PDLJOH4DSJQU
  60. ୯७ͳྫ 6OMPDLJOH4DSJQUɺ-PDLJOH4DSJQUͷॱͰ࣮ߦ͢Δ ελοΫʹσʔλͱ01ίʔυΛೖΕ͍ͯ͘ 01ίʔυΛελοΫʹೖΕͨͱ͖͸໋ྩʹԠͯ͡Լͷσʔλͭ·ͨ͸ෳ਺ ʹରͯ͠ԋࢉ͢Δ 60 -PDLJOH4DSJQU 6OMPDLJOH4DSJQU  01@"%%01@&26"-Λ࣮ߦ

        01@"%%  Ճࢉ        ༗ޮ 01@&26"-  01@"%%01@&26"- ಉ஋͔ ౳͍͠
  61. #JUDPJO4DSJQU TDSJQU#JUDPJO4DSJQUGSPN@TUSJOH 01@"%%01@&26"-z  TDSJQUSVO TDSJQU#JUDPJO4DSJQUGSPN@TUSJOH 01@"%%01@&26"-z  TDSJQUSVO 61

    irb(main):017:0> script = Bitcoin::Script.from_string("2 4 OP_ADD 6 OP_EQUAL").run => true irb(main):018:0> script = Bitcoin::Script.from_string("2 3 OP_ADD 6 OP_EQUAL").run => false irb(main):019:0> script = Bitcoin::Script.from_string("2 4 OP_ADD 6 OP_EQUAL") => #<Bitcoin::Script:0x0000000001be1c10 @chunks=["R", "T", "\x93", "V", "\x87"]> irb(main):020:0> script.run => true
  62. ࢀߟʣ11, 1BZUP1VCMJD,FZ TJH͸ൿີ伴Λ༻͍ͯੜ੒͞ΕΔॺ໊ɺ1VC,͸ެ։伴 62 -PDLJOH4DSJQU 6OMPDLJOH4DSJQU TJH1VC,01@$)&$,4*(Λ࣮ߦ TJH 1VC, TJH

    1VC, 536& ༗ޮ $)&$,4*( TJH 1VC,01@$)&$,4*( ॺ໊Λݕূ
  63. ࢀߟʣ11,) 1BZUP1VCMJD,FZ)BTIʢ11,ͷൃల൛ʣ ެ։伴ϋογϡΛ༻͍Δ͜ͱͰΞυϨεΛ୹͘දݱͰ͖Δ TDSJQU͸ʢʣ಺Ͱͷݺͼํ΋͋Δ 63 -PDLJOH4DSJQU TDSJQU1VC,FZ 6OMPDLJOH4DSJQU TDSJQU4JH TJH

    TJH1VC,01@%6101@)"4)1VC,)BTI01@&26"-7&3*': 01@$)&$,4*(Λ࣮ߦ TJH 536& 1VC, TJH 1VC, TJH 1VC, 1VC, 1VC, 1VC,)BTI TJH 1VC, 1VC,)BTI 1VC,)BTI TJH 1VC, 1VC,)BTI 1VC,)BTI TJH 1VC, 01@%61 )"4) ෳ੡ 01@&26"- ౳͍͠ TJH1VC, 01@%6101@)"4)1VC,)BTI 01@&26"-7&3*':01@$)&$,4*( ಉ஋͔ 4)"ͷޙ 3*1&.% ෳ੡
  64. ࢀߟʣ11,)ʢଓ͖ʣ ࢒Γ͸11,ͱಉ͡ 64 -PDLJOH4DSJQU 6OMPDLJOH4DSJQU TJH 1VC, TJH 1VC, 

    536& $)&$,4*( TJH1VC, 01@%6101@)"4)1VC,)BTI 01@&26"-7&3*':01@$)&$,4*( ॺ໊Λݕূ
  65. ࢀߟʣϚϧνγά NPGOʢOਓதNਓͷॺ໊ͰϩοΫղআͰ͖ΔʣϚϧνγά Α͋͘ΔPGͷྫ 65 -PDLJOH4DSJQU TDSJQU1VC,FZ 6OMPDLJOH4DSJQU TDSJQU4JH 01@TJH"4JH#1VC,"1VC,#1VC,$01@$)&$,.6-5*4*( )"4)

    01@TJH"TJH# 1VC,"1VC,#1VC,$ 01@$)&$,.6-5*4*( 536&  TJHOBUVSF#  1VCMJD,FZ$  $)&$,.6-5*4*( TJHOBUVSF" 1VCMJD,FZ# 1VCMJD,FZ" 
  66. CJUDPJOSC࢖༻ JSC ԼهͷίʔυΛෳ਺ߦؙ͝ͱίϐϖ 66 irb(main):001:0> require 'bitcoin' => true irb(main):002:0>

    require 'net/http' => true irb(main):003:0> require 'json' => false irb(main):004:0> Bitcoin.chain_params = :regtest => :regtest irb(main):005:0> RPCUSER="hoge" => "hoge" irb(main):006:0> RPCPASSWORD="hoge" => "hoge" irb(main):007:0> HOST="localhost" => "localhost" irb(main):008:0> PORT=18332 => 18332 irb(main):011:0> def bitcoinRPC(method,param) irb(main):012:1> http = Net::HTTP.new(HOST, PORT) irb(main):013:1> request = Net::HTTP::Post.new('/') irb(main):014:1> request.basic_auth(RPCUSER,RPCPASSWORD) irb(main):015:1> request.content_type = 'application/json' irb(main):016:1> request.body = {method: method, params: param, id: 'jsonrpc'}.to_json irb(main):017:1> JSON.parse(http.request(request).body)["result"] irb(main):018:1> end => :bitcoinRPC require 'bitcoin' require 'net/http' require 'json' Bitcoin.chain_params = :regtest RPCUSER="hoge" RPCPASSWORD="hoge" HOST="localhost" PORT=18332 def bitcoinRPC(method,param) http = Net::HTTP.new(HOST, PORT) request = Net::HTTP::Post.new('/') request.basic_auth(RPCUSER,RPCPASSWORD) request.content_type = 'application/json' request.body = {method: method, params: param, id: 'jsonrpc'}.to_json JSON.parse(http.request(request).body)["result"] end
  67. CJUDPJO31$Ͱ#JUDPJO$PSFΛૢ࡞ JSC NBJO CJUDPJO31$ bHFUCMPDLDIBJOJOGP` <>  BEESFTTCJUDPJO31$ bHFUOFXBEESFTT <>

     CJUDPJO31$ HFOFSBUFUPBEESFTT < BEESFTT> 67 irb(main):019:0> bitcoinRPC('getblockchaininfo',[]) => {"chain"=>"regtest", "blocks"=>259, "headers"=>259, "bestblockhash"=>"537f9822f97e2110fa8d04d7676855eef5c7628c425a2a2e271a49d6a0741480", "difficulty"=>4.656542373906925e-10, "mediantime"=>1574683242, "verificationprogress"=>1, "initialblockdownload"=>true, "chainwork"=>"0000000000000000000000000000000000000000000000000000000000000208", "size_on_disk"=>108511, "pruned"=>false, "softforks"=>{"bip34"=>{"type"=>"buried", "active"=>false, "height"=>500}, "bip66"=>{"type"=>"buried", "active"=>false, "height"=>1251}, "bip65"=>{"type"=>"buried", "active"=>false, "height"=>1351}, "csv"=>{"type"=>"buried", "active"=>false, "height"=>432}, "segwit"=>{"type"=>"buried", "active"=>true, "height"=>0}, "testdummy"=>{"type"=>"bip9", "bip9"=>{"status"=>"started", "bit"=>28, "start_time"=>0, "timeout"=>9223372036854775807, "since"=>144, "statistics"=>{"period"=>144, "threshold"=>108, "elapsed"=>116, "count"=>116, "possible"=>true}}, "active"=>false}}, "warnings"=>""}