以åã®èšäºïŒ
ããŒã1ããã³
ããŒã2 ïŒã§ã¯ãèªåãããŒãã§ããããšãæ°ã«ããªãå Žåã«ã¹ããŒãã³ã³ãã©ã¯ãã§åæ£ã¢ããªã±ãŒã·ã§ã³ã䜿çšããæ¹æ³ã«ã€ããŠèª¬æããŸããã ãããããŠãŒã¶ãŒãè¿œå ã®ã¢ã¯ã·ã§ã³ãå®è¡ããããšãäœåãªããããã»ã©ãããè¯ãçµæãåŸãããŸãã ã¹ããŒãã³ã³ãã©ã¯ãã䜿çšããã«ã¯ããã©ã€ããŒãããŒã䜿çšããŠãã©ã³ã¶ã¯ã·ã§ã³ã«çœ²åããå¿
èŠããããŸãããã®ãããæ®å¿µãªãããè¿œå ã®ã¢ã¯ã·ã§ã³ãªãã§ã¯å®è¡ã§ããŸããã ãã®èšäºã§ã¯ã2ã€ã®ã¢ãããŒããæ€èšããŸã.1ã€ç®ã¯ãWeb3ã©ã€ãã©ãªãšMetaMaskãã©ã°ã€ã³ã䜿çšããJavaScriptã®æ¬æ Œçãªåæ£ã¢ããªã±ãŒã·ã§ã³ïŒDAppïŒã2ã€ç®ã¯åæ§ã®ã¢ããªã±ãŒã·ã§ã³ã§ãããRuby on Rails APIãšEthereum.rb gemã䜿çšããŠãããã¯ãã§ãŒã³ã«ã¢ã¯ã»ã¹ããŸãã
å®éã®DAppãã©ã®ããã«æ©èœãããã瀺ãããã«ã
å
¬åŒã®äŸã«è§Šçºãããã¢ããªã±ãŒã·ã§ã³ãæ€èšããŠãã ããã æ祚ãšä»»æã®ãã©ã³ã¶ã¯ã·ã§ã³ã®å®è¡ã䌎ãæ°äž»äž»çŸ©ã®ä»£ããã«ã誰ã§ããéïŒãšãŒãã«ïŒã®åé
ã®ææ¡ãäœæããåå è
ãæ祚ããæéåŸã«æ祚ã®çµæã«å¿ããŠææ¡ãå±¥è¡ããããã©ããã®ç°¡æãã£ãªãã£ã³ã³ãã©ã¯ããäœæããŸãã
ãã®å Žåã®ã¹ããŒãã³ã³ãã©ã¯ãã®ããžãã¯ã¯ããã»ã©éèŠã§ã¯ãããŸãããç§ãã¡ã®ç®æšã¯ããŠãŒã¶ãŒããããã¯ãã§ãŒã³ãšå¯Ÿè©±ããããã®ãªãã·ã§ã³ã瀺ãããšã§ãã
䜿çšããããŒã«ãããå°ã詳ããæ€èšãããã®åŸãã¢ããªã±ãŒã·ã§ã³ã«çŽæ¥ç§»åããŸãã
䜿çšæžã¿ããŒã«
1.ã¡ã¿ãã¹ã¯
ããã¯Chromeãã©ãŠã¶çšã®ãã©ã°ã€ã³ã§ãããéçºè
ã¯Firefoxãèšç»ããŠãããšæžããŠããŸããããããŸã§ã®ãšããChromeã®ã¿ã§ãã
ãã¡ãããããŠã³ããŒãã§ããŸãã ãã©ã°ã€ã³ã¯2ã€ã®ããšãè¡ããŸãã
- ãªã¢ãŒããã¹ããä»ããŠç®çã®ã€ãŒãµãªã¢ã ãããã¯ãŒã¯ãžã®æ¥ç¶ãæäŸããããããŠãŒã¶ãŒã¯ãã¹ããå±éããå¿
èŠããããŸããã
- ãããã¯ãã§ãŒã³ãæäœããããã®æ°ããã¢ã«ãŠã³ããäœæããããæ¢åã®ã¢ã«ãŠã³ããã€ã³ããŒããããã§ããŸãã ããã«ããããŠãŒã¶ãŒãããŒã«ã«ã«ä¿åããç§å¯éµã§ãã©ã³ã¶ã¯ã·ã§ã³ã«çœ²åã§ããŸãã
ãã©ã°ã€ã³ã®äœ¿çšæ¹æ³ã®è©³çŽ°ã«ã€ããŠã¯ã
å
¬åŒããŒãžãŸãã¯
ãã¿ãã¬ã®äžãã©ã°ã€ã³ã§ã¯ãäžéšã®ãããã¯ãŒã¯åãã¯ãªãã¯ããŠãå®éã®ãããã¯ãŒã¯ãšãã¹ããããã¯ãŒã¯ã«æ¥ç¶ã§ããŸãã
å¿
èŠã«å¿ããŠãæ¢åã®ããŒãã€ã³ããŒãã§ããŸãããæ°ããããŒãäœæããæ¹ã䟿å©ã§ãã
GethãŸãã¯Mistã§äœæãããããŒãã€ã³ããŒãããå Žåã¯ãã€ã³ããŒãæã«JSONãã¡ã€ã«ãéžæãããã£ã¬ã¯ããªã/ .ethereum / <network> / keystoreã§ç®çã®ã¢ãã¬ã¹ã®ãã¡ã€ã«ãèŠã€ããŸãã å°ãªããšããã®èšäºã®å
¬éæç¹ã®Ubuntuã§ã¯ãJSONãã¡ã€ã«ãéãéã«ãã°ãããããšã«æ³šæããŠãã ããããã¡ã€ã«ãéžæãããšãMetaMaskãŠã£ã³ããŠãéããŠããŒãã€ã³ããŒããããŸããã ãã®å Žåãæ¡åŒµã¢ãã¬ã¹chrome-extensionã䜿çšããŠå¥ã®ã¿ãã§MetaMaskãéããŠã¿ãŠãã ããïŒ//nkbihfbeogaeaoehlefnkodbefgpgknn/popup.html
ãšããã§ããã¹ããããã¯ãŒã¯ãéžæããŠ[賌å
¥]ãæŒããšããã¹ããããŒããã£ã¹ããé
ä¿¡ãããªãœãŒã¹ãžã®ãªã³ã¯ãååŸã§ããŸãã Ropstenã®å Žåã§ãïŒèå£ãããšãŒãã«1ãã¯ãªãã¯ããã ãã§ïŒïŒ
2. MetaMaskãã©ã°ã€ã³ã§Web3.jsã©ã€ãã©ãªã䜿çšãã
Web3.jsã¯JavaScriptã©ã€ãã©ãªã§ããã
åã®èšäºã§Gethã§äœ¿çšãããã®ãšåãã§ãã MetaMaskã¯éããŠãããã¹ãŠã®ããŒãžã«Web3.jsãåã蟌ããããChrome Developer Toolsã®javascriptã³ã³ãœãŒã«ã§ç°¡åãªã³ãã³ããçŽæ¥ãã¹ãã§ããŸãã ãã®èšäºã®å·çæç¹ã§ãWeb3.jsã®çŸåšã®ããŒãžã§ã³ã¯0.20.1ã§ããããšã«æ³šæããããšãéèŠã§ãã ããŒãžã§ã³0.xxã®ããã¥ã¡ã³ãã¯
ãã¡ãããå
¥æã§ã
ãŸã ãããŒãžã§ã³1.0ã®ããã¥ã¡ã³ããšæ··åããªãã§ãã ããïŒ
ãªã³ã¯ ïŒã
2ã€ã®ã³ãã³ããå®è¡ããŸãã1ã€ã¯ããŒã¿ïŒäŸïŒã¢ã«ãŠã³ãæ®é«ïŒãåä¿¡ãã2ã€ç®ã¯å€æŽããŸãïŒããšãã°ã
åã®èšäºã® StringHolderã¹ããŒãã³ã³ãã©ã¯ãã§æååãèšå®ããŸãïŒã ãŸããMetaMaskã§ã¢ã«ãŠã³ããäœæããç®çã®ãããã¯ãŒã¯ïŒãã®å Žåã¯Ropsten Test NetworkïŒã«æ¥ç¶ããDeveloper Toolsã³ã³ãœãŒã«ã«ç§»åããããšãå¿ããªãã§ãã ããã
> web3.eth.getBalance(web3.eth.accounts[0], function(error, result) { console.log(web3.fromWei(result.toNumber())); } )
ã³ã³ãã©ã¯ãã¡ãœãããåŒã³åºããšãã¯ãã³ãŒã«ããã¯é¢æ°ãæåŸã®åŒæ°ãšããŠåŒã³åºãããšãå¿ããªãã§ãã ããã ãããè¡ãããšãã§ããŸãïŒ
> web3.eth.getBalance(web3.eth.accounts[0], console.log) null e {s: 1, e: 18, c: Array(2)} c:(2) [78950, 84540000000000] e:18 s:1 __proto__:Object
Web3.jsã¯ãæ°å€ã«
BigNumberã©ã€ãã©ãªã䜿çšããŸãã äžèšã®äŸã§ã¯ãåçã¯å€æãããã«è¡šç€ºãããŸãã
èªã¿åãã³ãã³ãã¯ããã«å®è¡ãããã¹ããŒãã³ã³ãã©ã¯ãïŒ
constant
ãšããŠããŒã¯ãããŠã
constant
ïŒã§ããŒã¿ãå€æŽããé¢æ°ãå®è¡ããå ŽåãMetaMaskã¯ãã©ã³ã¶ã¯ã·ã§ã³çœ²åãŠã£ã³ããŠã衚瀺ããŸãã ããã«ã€ããŠã¯ã
åã®èšäºã® StringHolderã³ã³ãã©ã¯ããéãããã®äžã®stringã¡ãœãããåŒã³åºããŠèª¬æããŸãã
> var address = "0x65cA73D13a2cc1dB6B92fd04eb4EBE4cEB70c5eC"; > var abi = [ { "constant": false, "inputs": [ { "name": "newString", "type": "string" } ], "name": "setString", "outputs": [], "payable": false, "type": "function" }, { "constant": true, "inputs": [], "name": "getString", "outputs": [ { "name": "", "type": "string", "value": "Hello World!" } ], "payable": false, "type": "function" } ]; > var contract = web3.eth.contract(abi); > var stringHolder = contract.at(address) > stringHolder.getString(console.log) null "Hello Dolly!!! 22" > stringHolder.setString("Hello from the other side!", console.log)
setStringã¡ãœãããåŒã³åºããåŸããã©ã³ã¶ã¯ã·ã§ã³ãšã¬ã¹ãšãšãŒãã«ã®æšå®ã³ã¹ãã«é¢ããæ
å ±ã確èªããããæ±ãããŠã£ã³ããŠã衚瀺ãããŸãã Submitãã¯ãªãã¯ããŸãã ã³ã³ãœãŒã«ã«ããã©ã³ã¶ã¯ã·ã§ã³ã®ããã·ã¥ã衚瀺ãããŸãã
ãã°ããããŠãè¡ãå€æŽãããããšã確èªããŸãã
> stringHolder.setString("Hello from the other side!", console.log) "0x4252c00ff25b690846ec8ad3b4266047a75a1708153bcac24066da9cb01e6db5" > stringHolder.getString(console.log) null "Hello from the other side!"
ãã¹ãŠãæ£åžžã«æ©èœããŸãã
3. Ethereum.rb
ããã¯ãRubyã®Ethereumãããã¯ãã§ãŒã³ïŒ
githubãžã®ãªã³ã¯ ïŒãæäœããããã®ã©ã€ãã©ãªã§ããçŸæç¹ã§ã¯ãæãç©æ¥µçã«ãµããŒããããŠããŸãã
irbã³ã³ãœãŒã«ããStringHolderã³ã³ãã©ã¯ããéããŠã¿ãŸãããã
> require âethereum.rbâ > abi = '[ { "constant": false, "inputs": [ { "name": "newString", "type": "string" } ], "name": "setString", "outputs": [], "payable": false, "type": "function" }, { "constant": true, "inputs": [], "name": "getString", "outputs": [ { "name": "", "type": "string", "value": "Hello World!" } ], "payable": false, "type": "function" } ]' > address = "0x65cA73D13a2cc1dB6B92fd04eb4EBE4cEB70c5eC" > contract = Ethereum::Contract.create(name: "StringHolder", address: address, abi: abi) > contract.call.get_string() âHello from the other side!â
ãã£ã¡ã«ã±ãŒã¹ïŒgetStringïŒã¯èªåçã«ã¹ããŒã¯ã±ãŒã¹ïŒget_stringïŒã«å€æãããŠããããšã«æ³šæããŠãã ããããã§ã®ã¡ãœããåŒã³åºãã®ç¹åŸŽã¯ãããŒã¿ãååŸããå¿
èŠãããå Žåã«ã®ã¿ãgetterã
call
ãä»ããŠ
call
ããããšã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ã§ã¯ãåæåŒã³åºãã®å Žåã¯
transact
ããéåæåŒã³åºãã®å Žåã¯
transact_and_wait
ãå¿
èŠã§ãã
ãã©ã³ã¶ã¯ã·ã§ã³ãäœæããã
set_string
é¢æ°ãåŒã³åºããŠã¿ãŸãããã 2ã€ã®æ¹æ³ããããŸãïŒunlockAccountïŒéæšå¥šïŒãšãã©ã³ã¶ã¯ã·ã§ã³ã«çœ²åïŒè©³çŽ°ã¯åŸè¿°ïŒã
> Ethereum::IpcClient.new.personal_unlock_account(Ethereum::IpcClient.new.eth_coinbase["result"], "<>")
ãã©ã³ã¶ã¯ã·ã§ã³ã®éä¿¡è
ïŒçŸåšããããã¯ã解é€ããŠãããã®ïŒãå²ãåœãŠãå¿
èŠããããŸãã
> contract.sender = Ethereum::IpcClient.new.eth_coinbase["result"]
次ã«ã
transact_and_wait
ãŸãã¯
transact
代å
¥ãã
transact_and_wait
call
ã
call
代ããã«ã»ãã¿ãŒãåŒã³åºãããšãã§ããŸãã
> contract.transact_and_wait.set_string(âHello darkness, my old friendâ)
ç§ãã¡ã¯çµãããåŸ
ã£ãŠããŸããç§ãã¡ã¯é»è©±ããŸã
> contract.call.get_string()
å€æŽã衚瀺ãããŸã-ãã¹ãŠãæ©èœããŸãã
DAppã¯äœããã¹ãã
åé¡ãå®åŒåããŸãã ã¢ã«ãŠã³ããæã€æ
åå£äœãè¡šãå¥çŽãå¿
èŠã§ãã ãã®çµç¹ã«ã¯ãå¯ä»ã®åé è
ãšææ¡ã®æ祚è
ã®äž¡æ¹ãšããŠè¡åã§ããç»é²ãŠãŒã¶ãŒãããå ŽåããããŸãã çµç¹ã®ã¢ã«ãŠã³ãããç»é²æžã¿ã¢ã«ãŠã³ãã®1ã€ã«ãéïŒãšãŒãã«ïŒã転éãããªãã¡ãŒãäœæããæ¹æ³ãå¿
èŠã§ãã äžåºŠã«ãã¹ãŠã®ãšãŒãã«ãåãããã¯ãªãããã«ãå¶éãå°å
¥ããŸã-æäŸã§ãããšãŒãã«ã¯1ã€ãŸã§ã§ãã 次ã«æ祚ãè¡ããïŒãè³æããŸãã¯ãå察ãæ祚ã§ããŸãïŒãç¹å®ã®æéïŒããããŒã¶ã«ãäœæãããç¬éãã5åïŒãŸã§ã«ã¯å®äºã§ããŸããã ç· ãåãåŸãæ祚ã¯åŒãç¶ãåãä»ããããŸãããæ祚ãå®äºããæ©äŒãããããå察ãããããè³æãã§çµããå Žåã¯ãçµç¹ã®ã¢ã«ãŠã³ãããåä¿¡è
ã®ã¢ã«ãŠã³ãã«ç©ºæ°ã移ããŸãã å察祚ãããã°-äœãããŸããã
äžè¬ã«ãã¢ããªã±ãŒã·ã§ã³ã¹ããŒã ã¯æ¬¡ã®ãšããã§ãã
2ã€ã®jsã¢ãžã¥ãŒã«ïŒBlockchain.jsãšBlockchainApi.jsïŒã¯ããããã¯ãã§ãŒã³ã®æäœãæ
åœããŸãã ãããã¯åãããšãè¡ããŸããæåã®ãã®ã¯Web3.jsã§åäœããMetaMaskããŒããä»ããŠãããã¯ãã§ãŒã³ã«çŽæ¥ã¢ã¯ã»ã¹ãã2ã€ç®ã¯Rails APIã«ajaxãªã¯ãšã¹ããè¡ããŸãã ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³èªäœã¯Reactã§èšè¿°ãããŠããã䜿çšãã2ã€ã®jsã¢ãžã¥ãŒã«ã«äŸåããŸããã
ãã£ãªãã£åºæ¬å¥çŽ
ã³ã³ãã©ã¯ãã¯åäžãã¡ã€ã«ã®åœ¢åŒã§ãããããç¹å¥ãªå±éæ¹æ³ã¯äœ¿çšããŸãããå°ãªããšã
Mistãä»ã㊠ãå°ãªããšã
Gethã³ãã³ãã©ã€ã³ã䜿çšããŠããããè¡ãããšãã§ããŸãã
ããããã³ãŒãã䜿çšã§ããŸãã äžè¬çã«ã圌ã®ã¹ããŒã ã¯æ¬¡ã®ããã«è¡šãããšãã§ããŸãã
è«çãããã¯ã®Charity.solå¥çŽã³ãŒããæ€èšããŠãã ããã ãŸããå¿
èŠãªãã¹ãŠã®å€æ°ã®èª¬æããããŸãã
uint public debatingPeriodInMinutes; // Proposal[] public proposals; // , uint public numProposals; // proposals uint public numMembers; // members mapping (address => uint) public memberId; // members address[] public members; //
ãããã³ã°ã䜿çšãããšããŠãŒã¶ãŒã®ã¢ãã¬ã¹ã®é
åã§ã€ã³ããã¯ã¹ãååŸã§ããŸãã ãã®ãããªã¢ãã¬ã¹ãæã€ãŠãŒã¶ãŒãååšããªãå Žåããã®ã¢ãã¬ã¹ãæã€ãŠãŒã¶ãŒãç»é²ãããŠãããã©ãããå€æããé¢æ°ã«åºã¥ããŠãã€ã³ããã¯ã¹0ãè¿ãããŸãã ããããããã«ããé
åã®èŠä»¶ãå°å
¥ãããŸãããŠãŒã¶ãŒã¯ã€ã³ããã¯ã¹1ããå§ãŸãé
åã«æ ŒçŽããå¿
èŠããããŸãããã®ããžãã¯ãæ
åœããã³ãŒãã«ã€ããŠã¯åŸã§èª¬æããŸãã äžæ¹ããªãã¡ãŒãä¿åããããã®æ§é ããããŸãã
struct Proposal { address recipient; // uint amount; // string description; // uint votingDeadline; // bool executed; // , bool proposalPassed; // , uint numberOfVotes; // int currentResult; // , ââ = +1, ââ = -1 Vote[] votes; // , mapping (address => bool) voted; // , - }
æ祚ã®æ§é ã¯ãåæã®é
åã«è¿œå ãããŸã
struct Vote { bool inSupport;
ãŠãŒã¶ãŒãç»é²ãããŠããå Žåã«ã®ã¿ãè¿œå ãããã¡ãœããã®å®è¡ãå¯èœã§ããããšãå¶åŸ¡ã§ãã修食åãæ€èšããŠãã ããã æ¢ã«è¿°ã¹ãããã«ãæ€èšŒã³ãŒãã¯ãååšããªããããã³ã°èŠçŽ ãã€ã³ããã¯ã¹
0
äžãããšããäºå®ã«åºã¥ããŠãããã€ã³ããã¯ã¹
1
ããå§ãŸããŠãŒã¶ãŒãä¿åããŸãã
modifier onlyMembers { require (memberId[msg.sender] != 0); // _; // }
msg
ã¯ãåŒã³åºãå
ã«é¢ããæ
å ±ãååŸã§ããæ§é ã§ãã ãã®å Žåã
msg.sender
ã¯ããã®ä¿®é£Ÿåã䜿çšããŠã¡ãœãããåŒã³åºããã¢ã«ãŠã³ãã®ã¢ãã¬ã¹ã§ãã
ãããã€æã«å®è¡ãããã³ã³ãã©ã¯ãã®ã³ã³ã¹ãã©ã¯ã¿ãŒã«ã€ããŠèª¬æããŸãã èšå®ããå¿
èŠãããã®ã¯ãåææ¡ã®æ祚ã«å²ãåœãŠãããæéã ãã§ãã ããã«ãã¡ã³ããŒé
åã®ãµã€ãºãå¢ãããŸããããã¯ããµã€ãºã«åºã¥ããŠãŠãŒã¶ãŒãè¿œå ãããŒãèŠçŽ ãäºçŽããããŸãŸã«ãªãããã§ãã
function Charity( uint _minutesForDebate ) payable {
ãŠãŒã¶ãŒãè¿œå ããæ©èœïŒ
function addMember(address _targetMember) { if (memberId[_targetMember] == 0) { // 0 , uint id; memberId[_targetMember] = members.length; // , id = members.length++; // members[id] = _targetMember; // } }
require
é¢æ°ã«æ³šæããŠãã ãã-å€ãããŒãžã§ã³ã®solidityã®
throw
ã眮ãæããŸããã
require
ã«
true
ãŸãã¯
false
ãæž¡ãã
require
ã
throw
ãšåæ§ã®ãã³ãã©ãŒãããªã¬ãŒããããã©ã³ã¶ã¯ã·ã§ã³å
šäœãããŒã«ããã¯ãããŸãã
ã¢ãã¬ã¹ããŠãŒã¶ãŒã®ãªã¹ãã«ãããã©ããã確èªããã«ã¯ã次ã®é¢æ°ã䜿çšããŸãã
function isMember( address _targetMember ) constant returns ( bool ) { return ( memberId[_targetMember] != 0 ); }
次ã®æ©èœã¯ãææ¡ãäœæããããšã§ããå¯ä»ã®åå人ã®äœæãweiã®ãšãŒãã«ã®éãããã³èª¬æè¡ãåãå
¥ããŸãã onlyMembers修食åããã®é¢æ°ã«é©çšãããŸããã€ãŸãããã¹ãŠã®ã³ãŒããå®è¡ãããåã«ãåŒã³åºãå
ã¢ã«ãŠã³ããç»é²ãããŠãããã©ããããã§ãã¯ãããŸãã ããã§ã¯ã
1 ether
ã
1 minutes
ãªã©ã®å€æã衚瀺ãããŸãã ãã®ãããªãµãã£ãã¯ã¹ã®å®å
šãªãªã¹ãã¯
ããã§èŠãããšãã§ã
ãŸã ããããã¯äŸ¿å®äžäœæãããŠãããå€ã«ã¯é©çšã§ããŸãããå€æ°ã«ã¯é©çšã§ããŸããã ããããå€æ°ã«é©çšããã«ã¯ãæ¥å°ŸèŸã«1ãè¿œå ããã ãã§ããããã¯ããã®äŸã§ã¯ç§ã«å€æããããã«è¡ãããŸãã
function newProposal( address _beneficiary, // uint _weiAmount, // wei string _description // ) onlyMembers returns (uint proposalID) { require( _weiAmount <= (1 ether) ); // 1 proposalID = proposals.length++; // 1 Proposal storage p = proposals[proposalID]; // p.recipient = _beneficiary; p.amount = _weiAmount; p.description = _description; p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes; // p.executed = false; // p.proposalPassed = false; p.numberOfVotes = 0; numProposals = proposalID + 1; // return proposalID; }
ããã§ã
now
ããŒã¯ãŒãã¯çŸåšã®æå»ã§ããããã©ã³ã¶ã¯ã·ã§ã³ãåŒã³åºãããæç¹ã§ã¯ãªãããããã¯ãäœæãããæç¹ã«æ³šæããŠãã ããã ãããã£ãŠãç· ãåãã¯ãããããŒã¶ã«ããããã¯ãã§ãŒã³ã§æ¢ã«äœæãããç¬éããã«ãŠã³ããããŸãã
ç§ãã¡ã®
proposals
ã¯
public
ãŠãããšããäºå®ã«ããããããããã®æ¹æ³ã§ã¯ãé
åã®åœ¢åŒã§æãåçŽãªãã£ãŒã«ãã®ã¿ãååŸã§ããŸãã ã€ãŸããã³ã³ãã©ã¯ãã®
proposals(1)
ãªã©ã®ã¡ãœãããåŒã³åºããšãã€ã³ããã¯ã¹
1
ããããŒã¶ã«ãé
å
{ recipient, amount, description, votingDeadline, executed, proposalPassed, numberOfVotes, currentResult }
ããæ§é å
ã®
votes
ããã³
voted
é
åã¯è¿ãããŸããã ããããæ祚ã衚瀺ããããã«ããŸãã¯æ祚ããæ©äŒãäžããããã«ããŠãŒã¶ãŒãç¹å®ã®ææ¡ã«æ祚ãããã©ããã«ã€ããŠã®æ
å ±ãå¿
èŠã§ãã ãããŠãããã1åã®åŒã³åºãã§è¡ãããšããå§ãããŸãããããã£ãŠãé³å£°ã¹ããŒã¿ã¹ãšãªãã¡ãŒIDãå¿
èŠãšããã¢ã«ãŠã³ããåãå
¥ããç¹å¥ãªé¢æ°
getProposal
ã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ã§è¡šç€ºããããã«Proposalæ§é ãèªã¿åããšãã«ãã®æ
å ±ãååŸããŸãã
function getProposal( address _member, uint _proposalNumber ) constant returns ( address, // uint, string, uint, bool, bool, uint, int, int ) { Proposal memory proposal = proposals[ _proposalNumber ];
ããã¯ãç¹å®ã®ãŠãŒã¶ãŒãç¹å®ã®ææ¡ã«æ祚ããæ¹æ³ãæ¢ãè£å©æ©èœã§ãã è¿ãããå€ïŒ
0
ãŠãŒã¶ãŒãæ祚ããªãã£ãå Žåã
1
ãŠãŒã¶ãŒããè³æãã«æ祚ããå Žåã
-1
æ祚ããå察ãã®å Žåã
function getVoted(address _member, uint _proposalNumber) constant returns(int) { Proposal storage p = proposals[_proposalNumber]; int result = 0; int true_int = 1; int false_int = -1; // for (uint i = 0; i < p.numberOfVotes; i++) { if (p.votes[i].voter == _member) // { result = p.votes[i].inSupport ? true_int : false_int; break; // } } return result; }
æ祚ïŒç¹å®ã®çªå·ã®ææ¡ã«ã€ããŠã¯ãçïŒè³æïŒãŸãã¯åœïŒå察ïŒã§æ祚ããŸãã
function vote( uint _proposalNumber, // , bool _supportsProposal // ) onlyMembers returns (uint voteID) { Proposal storage p = proposals[_proposalNumber]; // require (p.voted[msg.sender] != true); // p.voted[msg.sender] = true; // p.numberOfVotes++; // if (_supportsProposal) { // ââ p.currentResult++; // 1 } else { // p.currentResult--; // 1 } voteID = p.votes.length++; // p.votes[voteID] = Vote({inSupport: _supportsProposal, voter: msg.sender}); // return p.numberOfVotes; }
æåŸã®é¢æ°
executeProposal
ã¯ãæ祚ãå®äºããåä¿¡è
ã®ã¢ãã¬ã¹ã«
executeProposal
ãéä¿¡ããïŒãŸãã¯éä¿¡ããªãïŒæ©èœã
executeProposal
ãŸãã
function executeProposal(uint _proposalNumber) { // Proposal storage p = proposals[_proposalNumber]; require ( !(now < p.votingDeadline || p.executed) ); // 1) , 2) p.executed = true; // if (p.currentResult > 0) { // ââ require ( p.recipient.send(p.amount) ); // p.proposalPassed = true; // , } else { // ââ p.proposalPassed = false; // , } }
æåŸã«ãpayable修食åãæã€ç©ºã®é¢æ°ããããŸãã
function () payable {}
ããã¯ãå¥çŽã®äœæã«ç©ºæ°ãéãããã«å¿
èŠã§ãã äžè¬ã«ç©ºã®é¢æ°ã¯ãé¢æ°åŒã³åºãã§ã¯ãªããã¹ãŠã®ã¡ãã»ãŒãžãåä¿¡ããŠââåŠçããé¢æ°ã§ãã ç§ãã¡ãããå¿
èŠãããã®ã¯ãæ¯æãå¯èœã«ããããšã§ããããããã°ãéãããã¬ã¹ã¯è¿œå ã®ã¢ã¯ã·ã§ã³ãªãã§å¥çŽã«å
¥éãããŸãã ãã ãããã®ä¿®é£Ÿåã®ä»ã®é¢æ°ã¯ããã®å Žåãããšãã°
addMember
etherãéä¿¡ã§ããªãããšã«æ³šæããŠãã ããã
Web3.jsã䜿çšããã¢ããªã±ãŒã·ã§ã³ã®ããªãšãŒã·ã§ã³
äž»ãªã¢ããªã±ãŒã·ã§ã³ã·ããªãªïŒ
- ãŠãŒã¶ãŒã¯MetaMaskãä»ããŠRopstenãããã¯ãŒã¯ã«æ¥ç¶ããŸã
- ã¢ã«ãŠã³ãã«ãšãŒãã«ããªãå Žåãåäžã®ãã©ã³ã¶ã¯ã·ã§ã³ãå®äºããããšã¯äžå¯èœã§ãã ãšãŒãã«ãåãåãæ©èœãè¿œå ããŸãããããã¯ãå£åº§æ®é«ã0.1ãšãŒãã«æªæºã®å Žåã«å©çšå¯èœã«ãªããŸãã ããã¯ããããŒããã£ã¹ãã®è»¢éå
ã¢ãã¬ã¹ã䜿çšããŠajaxãªã¯ãšã¹ããè¡ããããµãŒãããŒãã£ãµãŒãã¹ãä»ããŠå®è£
ãããŸãã
- ã¹ããŒãã³ã³ãã©ã¯ãã䜿çšããåºæ¬ã¢ã¯ã·ã§ã³ã¯ããŠãŒã¶ãŒãçµç¹ã®ã¡ã³ããŒã«ãªã£ãåŸã«ã®ã¿äœ¿çšã§ããŸãã ãããè¡ãã«ã¯ãã¹ããŒãã³ã³ãã©ã¯ãã®addMemberã¡ãœãããåŒã³åºãããŸãã
- çµç¹ã®ã¡ã³ããŒã¯ãè³éæ¯æ¿ã®ææ¡ïŒä»¥äžãææ¡ãïŒãäœæããããæ¢åã®ææ¡ã«æ祚ã§ããŸãã
- ããããŒã¶ã«ã®æéãæºäºãããšïŒäœææé+ 5åïŒãããããŒã¶ã«ãå®äºããããšãå¯èœã«ãªããŸãããã®çµæãæ祚ã®åé
ã«å¿ããŠããããŒããã£ã¹ããæå®ãããã¢ãã¬ã¹ã«è»¢éããããã©ããã決ãŸããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®ãã¢ã¯ã
ãªã³ã¯ -MetaMaskããŒãžã§ã³ã§å
¥æã§ããŸãã
ãœãŒã¹ã³ãŒãã¯
ãã¡ãã§ãã
ç¹°ãè¿ããŸãããWeb3.jsã®çŸåšã®ããŒãžã§ã³ã0.20.1ã§ãããšããäºå®ã«æ³šç®ããŠãã ããã ããããããŒãžã§ã³1.0ã¯ãªãªãŒã¹ã®æºåããã§ã«æŽã£ãŠããããã®å€æŽã¯éåžžã«éèŠã§ãã åè¿°ããããã«ãMetaMaskã¯web3ãããŒãžã«åã蟌ã¿ãããã«äœ¿çšã§ããŸãã ããããã©ã€ãã©ãªã掻çºã«éçºãããŠããããŠãŒã¶ãŒã®ã¢ããªã±ãŒã·ã§ã³ã®æäœæ§ãä¿èšŒããå¿
èŠããããšããäºå®ãèãããšãããã¯ããŒãžã§ã³ã䜿çšããMetaMaskãåã蟌ãweb3ãªããžã§ã¯ããåå®çŸ©ããå¿
èŠããããŸãã
ããã§ã¯ã次ã®æ¹æ³ã§ãããè¡ããŸãã
initializeWeb3() { if (typeof web3 !== 'undefined') {
window.onload
ã€ãã³ãã®åŸã«ãããè¡ãå¿
èŠããããŸãã
ãã®ã³ãŒãã§è§£æ±ºãããéèªæãªåé¡ã®1ã€ã¯ãå
¬åŒããã¥ã¡ã³ãã§ææ¡ãããŠããããã«
window.web3 = new Web3(web3.currentProvider)
ãåçŽã«äœæãããšãããã©ã«ãã¢ã«ãŠã³ããéžæãããªãããšã§ãã
æ¢ã«è¿°ã¹ãããã«ãMetaMaskã§ãããªã¹ããããããã¯ãŒã¯ãéžæã§ããŸãã Ropstenãããã¯ãŒã¯äžã®å¥çŽã¢ãã¬ã¹ã䜿çšããŸããä»ã®ãããã¯ãŒã¯äžã®ãããã®ã¢ãã¬ã¹ã«æ¥ç¶ããããšãããšãçµæã¯äºæž¬ã§ããŸããã ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ãžã®ã¢ã¯ã»ã¹ãæäŸããåã«ããŠãŒã¶ãŒãåããããã¯ãŒã¯äžã«ãããã©ããã確èªããå¿
èŠããããŸãã 次ã®ã³ãã³ãã䜿çšããŠããããã¯ãŒã¯IDãååŸã§ããŸãã
web3.version.getNetwork(function (err, netId) {});
ããã§ãã®ãã§ãã¯ãè¡ããçµæãRopstenãããã¯ãŒã¯ã®idãšæ¯èŒããŸã-ããã¯3ã§ãã
ãã¹ãŠã®ãããã¯ãŒã¯ã®IDã®ãªã¹ãã¯ãããšãã°ãnet_versionã®èª¬æã§èŠãããšãã§ããŸãã
ãããã¯ãã§ãŒã³ãæäœããããã®ãã¹ãŠã®ããžãã¯ã¯ã
blockchain.jsãã¡ã€ã«ã«ãããŸãã
ããã«ã¯ããããã¯ãã§ãŒã³ããããŒã¿ãåä¿¡ããããã®é¢æ°ãšãããã¯ãã§ãŒã³å
ã®ããŒã¿ãå€æŽããé¢æ°ã®2çš®é¡ã®é¢æ°ããããŸãã web3.jsã®ã»ãšãã©ã®ã¡ãœããã¯éåæã«å®è¡ãããæåŸã®ãã©ã¡ãŒã¿ãŒãšããŠã³ãŒã«ããã¯ãåãå
¥ããŸãã å€ãã®å ŽåãããŒã¿ãååŸããããã«ããã€ãã®ã¡ãœãããåŒã³åºãå¿
èŠããããäžéšã®ã¡ãœããã®åŒã³åºãã¯ä»ã®ã¡ãœããã®çµæã«äŸåãããããPromiseã䜿çšãããšäŸ¿å©ã§ãã web3.jsã®ããŒãžã§ã³1.0ã§ã¯ãéåæã¡ãœããã¯ããã©ã«ãã§ãããã¹ãè¿ããŸãã
ãããã¯ãã§ãŒã³ããæ
å ±ãååŸãã1ã€ã®äŸã次ã«ç€ºããŸãã
getCurrentAccountInfo
é¢æ°ã¯ãçŸåšã®ã¢ã«ãŠã³ãã®ã¢ãã¬ã¹ãæ®é«ãããã³ãã®ã¢ã«ãŠã³ããçµç¹ã®ã¡ã³ããŒã§ãããã©ããã®ãã©ã°ãè¿ããŸãã
Blockchain.prototype.getCurrentAccountInfo = function() { const address = this.address; if (address == undefined) { return Promise.resolve({}); } const balancePromise = new Promise(function(resolve, reject) { web3.eth.getBalance(address, function(err, res) { err ? reject(err) : resolve(web3.fromWei(res).toNumber()); }); }); const authorizedPromise = new Promise(function(resolve, reject) { this.contractInstance.isMember(address, function(err, res) { err ? reject(err) : resolve(res); }); }.bind(this)); return new Promise(function(resolve, reject) { Promise.all([balancePromise, authorizedPromise]).then(function(data) { resolve({ address: address, balance: data[0], isMember: data[1] }); }); }); };
次ã«ããããã¯ãã§ãŒã³å
ã®ããŒã¿ãå€æŽããæ©èœãããšãã°ãåå è
ãçµç¹ã«è¿œå ããæ©èœãæ€èšããŸãã
Blockchain.prototype.becomeMember = function() { return new Promise(function(resolve, reject) { this.contractInstance.addMember(this.address, function(err, res) { err ? reject(err) : resolve(res); }); }.bind(this)); };
ã芧ã®ãšãããæ§æã¯åã®äŸãšå€ãããŸããããã®é¢æ°ãå®è¡ããã ãã§ããããã¯ãã§ãŒã³å
ã®ããŒã¿ãå€æŽãããã©ã³ã¶ã¯ã·ã§ã³ãäœæãããŸãã
ã¹ããŒãã³ã³ãã©ã¯ãã®é¢æ°ãåŒã³åºããšããã®çµæãšããŠãã©ã³ã¶ã¯ã·ã§ã³ãäœæãããMetaMaskã¯ãã®ãã©ã³ã¶ã¯ã·ã§ã³ã確èªãããæåŠãããããŠãŒã¶ãŒã«æ±ããŸãã ãŠãŒã¶ãŒããã©ã³ã¶ã¯ã·ã§ã³ã確èªãããšãé¢æ°ã¯ãã©ã³ã¶ã¯ã·ã§ã³ã®ããã·ã¥ãè¿ããŸãã
æããã§ãªããã€ã³ãã®1ã€ã¯ããã©ã³ã¶ã¯ã·ã§ã³ãæåãããã©ããã確èªããæ¹æ³ã§ãã
䜿çšãããã¬ã¹ã®éã«åºã¥ããŠããã©ã³ã¶ã¯ã·ã§ã³ã®ã¹ããŒã¿ã¹ãå€æã§ããŸãã 䜿çšå¯èœãªæ倧éã®ã¬ã¹ã䜿çšãããŠããå Žåãå®è¡äžã«ãšã©ãŒãçºçãããããã©ã³ã¶ã¯ã·ã§ã³ãå®äºããã®ã«ååãªã¬ã¹ããããŸããã§ããã 次ã®ããã«ã¹ããŒã¿ã¹ã確èªããŸãã
Blockchain.prototype.checkTransaction = function(transaction) { const txPromise = new Promise(function(resolve, reject) { web3.eth.getTransaction(transaction.transactionHash, function(err, res) { err ? reject(err) : resolve(res); }); }); const txReceiptPromise = new Promise(function(resolve, reject) { web3.eth.getTransactionReceipt(transaction.transactionHash, function(err, res) { err ? reject(err) : resolve(res); }); }); return new Promise(function(resolve, reject) { Promise.all([txPromise, txReceiptPromise]).then(function(res) { const tx = res[0]; const txReceipt = res[1]; const succeeded = txReceipt && txReceipt.blockNumber && txReceipt.gasUsed < tx.gas; const failed = txReceipt && txReceipt.blockNumber && txReceipt.gasUsed == tx.gas; let state = transactionStates.STATE_PENDING; if (succeeded) { state = transactionStates.STATE_SUCCEEDED; } else if (failed) { state = transactionStates.STATE_FAILED; } resolve(state); }); }); };
, localStorage , . â
transactions-storage.js .
Ruby on Rails ethereum.rb
- , . , . , , , . - , . . , web3.js, , . Ruby on Rails, ethereum.rb, , web3.js.
â Rails API .
ãœãŒã¹ã³ãŒãã¯
ãã¡ãã§ãã
ethereum.rb, , blockchain.js.
, , , .
â , . , , LocalStorage , API.
:
- Create Account, , , .
- API auth token .
- .
js , â , . â .
def proposals(address=nil) count = @contract_instance.call.num_proposals to = count - 1 from = count > PROPOSALS_LIMIT ? count - PROPOSALS_LIMIT : 0 res = (from..to).map do |idx| proposal = if address @contract_instance.call.get_proposal(address, idx) else @contract_instance.call.proposals(idx) end Proposal.new(proposal, idx) end res.sort_by(&:index).reverse end
, â , .
Eth . .
def self.new_account new_key = Eth::Key.new return new_key.address.downcase, new_key.private_hex end def signed_transactions(private_key_hex) key = Eth::Key.new priv: private_key_hex
signed_transactions
â , .
, Eth.
key
. ethereum.rb
key
. , , , .
signed_transactions
Proposal,
executeProposal
:
def finish_proposal(proposal_index, options={}) tx = signed_transactions(options[:private_key]) do |contract_instance| contract_instance.transact.execute_proposal(proposal_index) end tx.id end
. , js .
def transaction_status(tx_hash) tx = @client.eth_get_transaction_by_hash(tx_hash)['result'] tx_receipt = @client.eth_get_transaction_receipt(tx_hash)['result'] if tx_receipt block_number = tx_receipt['blockNumber'] gas_used = tx_receipt['gasUsed'].to_i(16) gas = tx['gas'].to_i(16) { succeeded: block_number && gas_used < gas, failed: block_number && gas_used == gas } end end
.
- , â
0xe79d8738f0769ec69f09cef4cd497c9cc477733e
â Ropsten.
çµæã¯äœã§ããïŒ
, . Ruby MetaMask . , , , javascript ruby. .
. !
Ethereum:
1:2: Web3.js