如何在以太坊构建去中心化应用(dapp)

背景

现在我们耳熟能详的是web2.0架构,中心化系统,比如说我们现在用的简书,如果有一天简书没有人维护了关闭了,那么我的所有信息都会随之而去,而去中心化系统可以完全解决这个问题,比如ipfs-星际文件系统,做为区块链大容量数据的存储系统,其实这两年区块链真正能够火起来我觉得得益于以太坊的诞生,可以实现在区块链上编程,因为以太坊每次和区块链交互都需要gas,而且gas和你的信息量成正相关,所以就造成了很多数据不得不存储在中心化的系统中,ipfs的出现可以说解决了区块链存储的问题,但是以太坊的tps是一个问题,但是技术就是这样一步步发展的,下面的这张图可以简单的做了一种参考,感兴趣的可以去搜搜这些dapp或者平台

  • web3.0.png

概述

本项目教你如何在区块链上面建一个去中心化应用,当然这个应用不会很复杂,只是一个简单的示例,构建一个去中心化的投票系统,其实美国大选完全可以基于这样的应用去做,匿名而且每人只有一票

项目结构

structure.png

合约分析

pragma solidity ^0.4.11;

contract Voting {
  //存储在区块链上的一个map key是账户地址 value是票数
  mapping (bytes32 => uint8) public votesReceived;
  
  //所有参与竞选的候选人
  bytes32[] public candidateList;

  //构造函数 在合约发布的时候把所有候选人都传进去
  function Voting(bytes32[] candidateNames) public {
    candidateList = candidateNames;
  }
  //查询某个候选人的票数 不会修改区块链上的数据 所以是view
  function totalVotesFor(bytes32 candidate) public view returns (uint8) {
    assert((validCandidate(candidate) == true));
    return votesReceived[candidate];
  }

  //给某个候选人投票 修改区块链上的map数据,需要miner打包确认
  function voteForCandidate(bytes32 candidate) public {
    assert((validCandidate(candidate) == true)) ;
    votesReceived[candidate] += 1;
  }
  //验证某个候选人是不是有效的候选人,也就是这个候选人
  //在不在我们发布智能合约时的那个参数列表中
  function validCandidate(bytes32 candidate) public view returns (bool) {
    for(uint i = 0; i < candidateList.length; i++) {
      if (candidateList[i] == candidate) {
        return true;
      }
    }
    return false;
  }
}

运行效果图

  • dapp端操作


    image.png

    在界面上面输入候选人的名字就可以投票了

  • 以太坊日志


    image.png

    每次投票可以理解成一个transaction,后台可以看到对应的日志信息

依赖

  • ethereumjs-testrpc
  • web3@0.20.1
  • solc

用npm安装缺少的依赖npm. nodejs 的安装就不做概述了

> git clone https://github.com/myyan/FirstDapp.git
> cd FirstDapp
> npm install  安装依赖

使用

在依赖安装完成后执行下面的命令 ethereum_test_rpc

node_modules/ethereumjs-testrpc/build/cli.node.js

接着打开node的终端 执行下面命令在区块链上部署智能合约

# heiqie /first_dapp on git:master o [20:05:18]
$ node
# 引入web3依赖
> Web3 = require('web3')
# 和本地的以太坊平台连接
> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
# 读取智能合约
> code = fs.readFileSync('Voting.sol').toString()
# 引入solidity语言编译器
> solc = require('solc')
# 编译
> compiledCode = solc.compile(code)
# 解析abi
> abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface)
# 通过abi创建合约Definition
> VotingContract = web3.eth.contract(abiDefinition)
# 获取合约二进制代码
> byteCode = compiledCode.contracts[':Voting'].bytecode
# 部署合约到以太坊平台(区块链)
> deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000})
> contractInstance = VotingContract.at(deployedContract.address)

实战

  • 执行结果
# heiqie @ heiqiedeMacBook-Pro in ~/code/FirstDapp on git:master x [20:51:19] C:1
$ node
>  Web3 = require('web3')
{ [Function: Web3]
  providers:
   { HttpProvider: [Function: HttpProvider],
     IpcProvider: [Function: IpcProvider] } }
>  web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
Web3 {
  _requestManager:
   RequestManager {
     provider:
      HttpProvider {
        host: 'http://localhost:8545',
        timeout: 0,
        user: undefined,
        password: undefined,
        headers: undefined },
     polls: {},
     timeout: null },
  currentProvider:
   HttpProvider {
     host: 'http://localhost:8545',
     timeout: 0,
     user: undefined,
     password: undefined,
     headers: undefined },
  eth:
   Eth {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     getBalance: { [Function: send] request: [Function: bound ], call: 'eth_getBalance' },
     getStorageAt: { [Function: send] request: [Function: bound ], call: 'eth_getStorageAt' },
     getCode: { [Function: send] request: [Function: bound ], call: 'eth_getCode' },
     getBlock: { [Function: send] request: [Function: bound ], call: [Function: blockCall] },
     getUncle: { [Function: send] request: [Function: bound ], call: [Function: uncleCall] },
     getCompilers: { [Function: send] request: [Function: bound ], call: 'eth_getCompilers' },
     getBlockTransactionCount:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: getBlockTransactionCountCall] },
     getBlockUncleCount:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: uncleCountCall] },
     getTransaction:
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionByHash' },
     getTransactionFromBlock:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: transactionFromBlockCall] },
     getTransactionReceipt:
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionReceipt' },
     getTransactionCount: { [Function: send] request: [Function: bound ], call: 'eth_getTransactionCount' },
     call: { [Function: send] request: [Function: bound ], call: 'eth_call' },
     estimateGas: { [Function: send] request: [Function: bound ], call: 'eth_estimateGas' },
     sendRawTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendRawTransaction' },
     signTransaction: { [Function: send] request: [Function: bound ], call: 'eth_signTransaction' },
     sendTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendTransaction' },
     sign: { [Function: send] request: [Function: bound ], call: 'eth_sign' },
     compile: { solidity: [Object], lll: [Object], serpent: [Object] },
     submitWork: { [Function: send] request: [Function: bound ], call: 'eth_submitWork' },
     getWork: { [Function: send] request: [Function: bound ], call: 'eth_getWork' },
     coinbase: [Getter],
     getCoinbase: { [Function: get] request: [Function: bound ] },
     mining: [Getter],
     getMining: { [Function: get] request: [Function: bound ] },
     hashrate: [Getter],
     getHashrate: { [Function: get] request: [Function: bound ] },
     syncing: [Getter],
     getSyncing: { [Function: get] request: [Function: bound ] },
     gasPrice: [Getter],
     getGasPrice: { [Function: get] request: [Function: bound ] },
     accounts: [Getter],
     getAccounts: { [Function: get] request: [Function: bound ] },
     blockNumber: [Getter],
     getBlockNumber: { [Function: get] request: [Function: bound ] },
     protocolVersion: [Getter],
     getProtocolVersion: { [Function: get] request: [Function: bound ] },
     iban:
      { [Function: Iban]
        fromAddress: [Function],
        fromBban: [Function],
        createIndirect: [Function],
        isValid: [Function] },
     sendIBANTransaction: [Function: bound transfer] },
  db:
   DB {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     putString: { [Function: send] request: [Function: bound ], call: 'db_putString' },
     getString: { [Function: send] request: [Function: bound ], call: 'db_getString' },
     putHex: { [Function: send] request: [Function: bound ], call: 'db_putHex' },
     getHex: { [Function: send] request: [Function: bound ], call: 'db_getHex' } },
  shh:
   Shh {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     version: { [Function: send] request: [Function: bound ], call: 'shh_version' },
     info: { [Function: send] request: [Function: bound ], call: 'shh_info' },
     setMaxMessageSize: { [Function: send] request: [Function: bound ], call: 'shh_setMaxMessageSize' },
     setMinPoW: { [Function: send] request: [Function: bound ], call: 'shh_setMinPoW' },
     markTrustedPeer: { [Function: send] request: [Function: bound ], call: 'shh_markTrustedPeer' },
     newKeyPair: { [Function: send] request: [Function: bound ], call: 'shh_newKeyPair' },
     addPrivateKey: { [Function: send] request: [Function: bound ], call: 'shh_addPrivateKey' },
     deleteKeyPair: { [Function: send] request: [Function: bound ], call: 'shh_deleteKeyPair' },
     hasKeyPair: { [Function: send] request: [Function: bound ], call: 'shh_hasKeyPair' },
     getPublicKey: { [Function: send] request: [Function: bound ], call: 'shh_getPublicKey' },
     getPrivateKey: { [Function: send] request: [Function: bound ], call: 'shh_getPrivateKey' },
     newSymKey: { [Function: send] request: [Function: bound ], call: 'shh_newSymKey' },
     addSymKey: { [Function: send] request: [Function: bound ], call: 'shh_addSymKey' },
     generateSymKeyFromPassword:
      { [Function: send]
        request: [Function: bound ],
        call: 'shh_generateSymKeyFromPassword' },
     hasSymKey: { [Function: send] request: [Function: bound ], call: 'shh_hasSymKey' },
     getSymKey: { [Function: send] request: [Function: bound ], call: 'shh_getSymKey' },
     deleteSymKey: { [Function: send] request: [Function: bound ], call: 'shh_deleteSymKey' },
     post: { [Function: send] request: [Function: bound ], call: 'shh_post' } },
  net:
   Net {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     listening: [Getter],
     getListening: { [Function: get] request: [Function: bound ] },
     peerCount: [Getter],
     getPeerCount: { [Function: get] request: [Function: bound ] } },
  personal:
   Personal {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     newAccount: { [Function: send] request: [Function: bound ], call: 'personal_newAccount' },
     importRawKey: { [Function: send] request: [Function: bound ], call: 'personal_importRawKey' },
     unlockAccount: { [Function: send] request: [Function: bound ], call: 'personal_unlockAccount' },
     ecRecover: { [Function: send] request: [Function: bound ], call: 'personal_ecRecover' },
     sign: { [Function: send] request: [Function: bound ], call: 'personal_sign' },
     sendTransaction:
      { [Function: send]
        request: [Function: bound ],
        call: 'personal_sendTransaction' },
     lockAccount: { [Function: send] request: [Function: bound ], call: 'personal_lockAccount' },
     listAccounts: [Getter],
     getListAccounts: { [Function: get] request: [Function: bound ] } },
  bzz:
   Swarm {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     blockNetworkRead: { [Function: send] request: [Function: bound ], call: 'bzz_blockNetworkRead' },
     syncEnabled: { [Function: send] request: [Function: bound ], call: 'bzz_syncEnabled' },
     swapEnabled: { [Function: send] request: [Function: bound ], call: 'bzz_swapEnabled' },
     download: { [Function: send] request: [Function: bound ], call: 'bzz_download' },
     upload: { [Function: send] request: [Function: bound ], call: 'bzz_upload' },
     retrieve: { [Function: send] request: [Function: bound ], call: 'bzz_retrieve' },
     store: { [Function: send] request: [Function: bound ], call: 'bzz_store' },
     get: { [Function: send] request: [Function: bound ], call: 'bzz_get' },
     put: { [Function: send] request: [Function: bound ], call: 'bzz_put' },
     modify: { [Function: send] request: [Function: bound ], call: 'bzz_modify' },
     hive: [Getter],
     getHive: { [Function: get] request: [Function: bound ] },
     info: [Getter],
     getInfo: { [Function: get] request: [Function: bound ] } },
  settings: Settings { defaultBlock: 'latest', defaultAccount: undefined },
  version:
   { api: '0.20.5',
     node: [Getter],
     getNode: { [Function: get] request: [Function: bound ] },
     network: [Getter],
     getNetwork: { [Function: get] request: [Function: bound ] },
     ethereum: [Getter],
     getEthereum: { [Function: get] request: [Function: bound ] },
     whisper: [Getter],
     getWhisper: { [Function: get] request: [Function: bound ] } },
  providers:
   { HttpProvider: [Function: HttpProvider],
     IpcProvider: [Function: IpcProvider] },
  _extend:
   { [Function: ex]
     formatters:
      { inputDefaultBlockNumberFormatter: [Function: inputDefaultBlockNumberFormatter],
        inputBlockNumberFormatter: [Function: inputBlockNumberFormatter],
        inputCallFormatter: [Function: inputCallFormatter],
        inputTransactionFormatter: [Function: inputTransactionFormatter],
        inputAddressFormatter: [Function: inputAddressFormatter],
        inputPostFormatter: [Function: inputPostFormatter],
        outputBigNumberFormatter: [Function: outputBigNumberFormatter],
        outputTransactionFormatter: [Function: outputTransactionFormatter],
        outputTransactionReceiptFormatter: [Function: outputTransactionReceiptFormatter],
        outputBlockFormatter: [Function: outputBlockFormatter],
        outputLogFormatter: [Function: outputLogFormatter],
        outputPostFormatter: [Function: outputPostFormatter],
        outputSyncingFormatter: [Function: outputSyncingFormatter] },
     utils:
      { padLeft: [Function: padLeft],
        padRight: [Function: padRight],
        toHex: [Function: toHex],
        toDecimal: [Function: toDecimal],
        fromDecimal: [Function: fromDecimal],
        toUtf8: [Function: toUtf8],
        toAscii: [Function: toAscii],
        fromUtf8: [Function: fromUtf8],
        fromAscii: [Function: fromAscii],
        transformToFullName: [Function: transformToFullName],
        extractDisplayName: [Function: extractDisplayName],
        extractTypeName: [Function: extractTypeName],
        toWei: [Function: toWei],
        fromWei: [Function: fromWei],
        toBigNumber: [Function: toBigNumber],
        toTwosComplement: [Function: toTwosComplement],
        toAddress: [Function: toAddress],
        isBigNumber: [Function: isBigNumber],
        isStrictAddress: [Function: isStrictAddress],
        isAddress: [Function: isAddress],
        isChecksumAddress: [Function: isChecksumAddress],
        toChecksumAddress: [Function: toChecksumAddress],
        isFunction: [Function: isFunction],
        isString: [Function: isString],
        isObject: [Function: isObject],
        isBoolean: [Function: isBoolean],
        isArray: [Function: isArray],
        isJson: [Function: isJson],
        isBloom: [Function: isBloom],
        isTopic: [Function: isTopic] },
     Method: [Function: Method],
     Property: [Function: Property] } }
>  code = fs.readFileSync('voting.sol').toString()
'pragma solidity ^0.4.11;\n\ncontract Voting {\n  \n  mapping (bytes32 => uint8) public votesReceived;\n  \n  \n  bytes32[] public candidateList;\n\n  function Voting(bytes32[] candidateNames) public {\n    candidateList = candidateNames;\n  }\n\n  function totalVotesFor(bytes32 candidate) public view returns (uint8) {\nassert((validCandidate(candidate) == true));\n    return votesReceived[candidate];\n  }\n\n  function voteForCandidate(bytes32 candidate) public {\n    assert((validCandidate(candidate) == true)) ;\n    votesReceived[candidate] += 1;\n  }\n\n  function validCandidate(bytes32 candidate) public view returns (bool) {\n    for(uint i = 0; i < candidateList.length; i++) {\n      if (candidateList[i] == candidate) {\n        return true;\n      }\n    }\n    return false;\n  }\n}\n'
>  solc = require('solc')
{ version: [Function],
  semver: [Function: versionToSemver],
  license: [Function],
  compile: [Function: compile],
  compileStandard: [Function: compileStandard],
  compileStandardWrapper: [Function: compileStandardWrapper],
  linkBytecode: [Function: linkBytecode],
  supportsMulti: true,
  supportsImportCallback: true,
  supportsStandard: true,
  loadRemoteVersion: [Function: loadRemoteVersion],
  setupMethods: [Function: setupMethods] }
>  compiledCode = solc.compile(code)
{ contracts:
   { ':Voting':
      { assembly: [Object],
        bytecode: '6060604052341561000f57600080fd5b6040516103e23803806103e2833981016040528080518201919050508060019080519060200190610041929190610048565b50506100c0565b82805482825590600052602060002090810192821561008a579160200282015b82811115610089578251829060001916905591602001919060010190610068565b5b509050610097919061009b565b5090565b6100bd91905b808211156100b95760008160009055506001016100a1565b5090565b90565b610313806100cf6000396000f30060606040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632f265cf714610072578063392e6678146100b35780637021939f146100f2578063b13c744b14610133578063cc9ab26714610172575b600080fd5b341561007d57600080fd5b610097600480803560001916906020019091905050610199565b604051808260ff1660ff16815260200191505060405180910390f35b34156100be57600080fd5b6100d86004808035600019169060200190919050506101e2565b604051808215151515815260200191505060405180910390f35b34156100fd57600080fd5b610117600480803560001916906020019091905050610242565b604051808260ff1660ff16815260200191505060405180910390f35b341561013e57600080fd5b6101546004808035906020019091905050610262565b60405180826000191660001916815260200191505060405180910390f35b341561017d57600080fd5b610197600480803560001916906020019091905050610286565b005b6000600115156101a8836101e2565b15151415156101b357fe5b600080836000191660001916815260200190815260200160002060009054906101000a900460ff169050919050565b600080600090505b60018054905081101561023757826000191660018281548110151561020b57fe5b90600052602060002090015460001916141561022a576001915061023c565b80806001019150506101ea565b600091505b50919050565b60006020528060005260406000206000915054906101000a900460ff1681565b60018181548110151561027157fe5b90600052602060002090016000915090505481565b60011515610293826101e2565b151514151561029e57fe5b6001600080836000191660001916815260200190815260200160002060008282829054906101000a900460ff160192506101000a81548160ff021916908360ff160217905550505600a165627a7a72305820d656e68956e578363e4124e152b2a002428282cc8f56349a55e77a8e807086fc0029',
        functionHashes: [Object],
        gasEstimates: [Object],
        interface: '[{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"validCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]',
        metadata: '{"compiler":{"version":"0.4.20+commit.3155dd80"},"language":"Solidity","output":{"abi":[{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"validCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}],"devdoc":{"methods":{}},"userdoc":{"methods":{}}},"settings":{"compilationTarget":{"":"Voting"},"libraries":{},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"":{"keccak256":"0x2f024c32b1df451474b79a0fa2251bd739c93f72aa95360f550d68a94076a182","urls":["bzzr://c17e0fc53ee8f32b764f7ce2b035287f8d7515dec3f9d6e46ce5884de814fe76"]}},"version":1}',
        opcodes: 'PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE ISZERO PUSH2 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x3E2 CODESIZE SUB DUP1 PUSH2 0x3E2 DUP4 CODECOPY DUP2 ADD PUSH1 0x40 MSTORE DUP1 DUP1 MLOAD DUP3 ADD SWAP2 SWAP1 POP POP DUP1 PUSH1 0x1 SWAP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 PUSH2 0x41SWAP3 SWAP2 SWAP1 PUSH2 0x48 JUMP JUMPDEST POP POP PUSH2 0xC0 JUMP JUMPDEST DUP3 DUP1 SLOAD DUP3 DUP3 SSTORE SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256SWAP1 DUP2 ADD SWAP3 DUP3 ISZERO PUSH2 0x8A JUMPI SWAP2 PUSH1 0x20 MUL DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH2 0x89 JUMPI DUP3 MLOAD DUP3 SWAP1 PUSH1 0x0 NOT AND SWAP1 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH2 0x68 JUMP JUMPDEST JUMPDEST POP SWAP1 POP PUSH2 0x97 SWAP2 SWAP1 PUSH2 0x9B JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST PUSH2 0xBD SWAP2 SWAP1 JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0xB9 JUMPI PUSH1 0x0 DUP2 PUSH1 0x0 SWAP1 SSTORE POP PUSH1 0x1 ADD PUSH2 0xA1 JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST SWAP1 JUMP JUMPDEST PUSH2 0x313 DUP1 PUSH2 0xCF PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x6D JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x2F265CF7 EQ PUSH2 0x72 JUMPI DUP1 PUSH4 0x392E6678 EQ PUSH2 0xB3 JUMPI DUP1 PUSH4 0x7021939F EQ PUSH2 0xF2 JUMPI DUP1 PUSH4 0xB13C744B EQ PUSH2 0x133 JUMPI DUP1 PUSH4 0xCC9AB267 EQ PUSH2 0x172 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE ISZERO PUSH2 0x7D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x97 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD PUSH1 0x0 NOT AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP2 SWAP1 POP POP PUSH2 0x199 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE ISZERO PUSH2 0xBE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xD8 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD PUSH1 0x0 NOT AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP2 SWAP1 POP POP PUSH2 0x1E2 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE ISZERO PUSH2 0xFD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x117 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD PUSH1 0x0 NOT AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP2 SWAP1 POP POP PUSH2 0x242 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE ISZERO PUSH2 0x13E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x154 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP2 SWAP1 POP POP PUSH2 0x262 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE ISZERO PUSH2 0x17D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x197 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD PUSH1 0x0 NOT AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP2 SWAP1 POP POP PUSH2 0x286 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 PUSH1 0x1 ISZERO ISZERO PUSH2 0x1A8 DUP4 PUSH2 0x1E2 JUMP JUMPDEST ISZERO ISZERO EQ ISZERO ISZERO PUSH2 0x1B3 JUMPI INVALID JUMPDEST PUSH1 0x0 DUP1 DUP4 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 SWAP1 POP JUMPDEST PUSH1 0x1 DUP1 SLOAD SWAP1 POP DUP2 LT ISZERO PUSH2 0x237 JUMPI DUP3 PUSH1 0x0 NOT AND PUSH1 0x1 DUP3 DUP2 SLOAD DUP2 LT ISZERO ISZERO PUSH2 0x20B JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 ADD SLOAD PUSH1 0x0 NOT AND EQ ISZERO PUSH2 0x22A JUMPI PUSH1 0x1 SWAP2 POP PUSH2 0x23CJUMP JUMPDEST DUP1 DUP1 PUSH1 0x1 ADD SWAP2 POP POP PUSH2 0x1EA JUMP JUMPDEST PUSH1 0x0 SWAP2 POP JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 MSTORE DUP1 PUSH1 0x0 MSTORE PUSH1 0x40 PUSH1 0x0 KECCAK256 PUSH1 0x0 SWAP2 POP SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x1 DUP2 DUP2 SLOAD DUP2 LT ISZERO ISZERO PUSH2 0x271 JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 ADD PUSH1 0x0 SWAP2 POP SWAP1 POP SLOAD DUP2 JUMP JUMPDEST PUSH1 0x1 ISZERO ISZERO PUSH2 0x293 DUP3 PUSH2 0x1E2 JUMP JUMPDEST ISZERO ISZERO EQ ISZERO ISZERO PUSH2 0x29E JUMPI INVALID JUMPDEST PUSH1 0x1 PUSH1 0x0 DUP1 DUP4 PUSH1 0x0 NOT AND PUSH1 0x0 NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP3 DUP3DUP3 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND ADD SWAP3 POP PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 PUSH1 0xFF AND MULOR SWAP1 SSTORE POP POP JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xd6 JUMP 0xe6 DUP10 JUMP 0xe5 PUSH25 0x363E4124E152B2A002428282CC8F56349A55E77A8E807086FC STOP 0x29 ',
        runtimeBytecode: '60606040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632f265cf714610072578063392e6678146100b35780637021939f146100f2578063b13c744b14610133578063cc9ab26714610172575b600080fd5b341561007d57600080fd5b610097600480803560001916906020019091905050610199565b604051808260ff1660ff16815260200191505060405180910390f35b34156100be57600080fd5b6100d86004808035600019169060200190919050506101e2565b604051808215151515815260200191505060405180910390f35b34156100fd57600080fd5b610117600480803560001916906020019091905050610242565b604051808260ff1660ff16815260200191505060405180910390f35b341561013e57600080fd5b6101546004808035906020019091905050610262565b60405180826000191660001916815260200191505060405180910390f35b341561017d57600080fd5b610197600480803560001916906020019091905050610286565b005b6000600115156101a8836101e2565b15151415156101b357fe5b600080836000191660001916815260200190815260200160002060009054906101000a900460ff169050919050565b600080600090505b60018054905081101561023757826000191660018281548110151561020b57fe5b90600052602060002090015460001916141561022a576001915061023c565b80806001019150506101ea565b600091505b50919050565b60006020528060005260406000206000915054906101000a900460ff1681565b60018181548110151561027157fe5b90600052602060002090016000915090505481565b60011515610293826101e2565b151514151561029e57fe5b6001600080836000191660001916815260200190815260200160002060008282829054906101000a900460ff160192506101000a81548160ff021916908360ff160217905550505600a165627a7a72305820d656e68956e578363e4124e152b2a002428282cc8f56349a55e77a8e807086fc0029',
        srcmap: '26:746:0:-;;;141:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;212:14;196:13;:30;;;;;;;;;;;;:::i;:::-;;141:90;26:746;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;',
        srcmapRuntime: '26:746:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;235:161;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;546:224;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;400:142;;;;;;;;;;;;;;;;;;;;;;;;;;;;;235:161;298:5;348:4;319:33;;:25;334:9;319:14;:25::i;:::-;:33;;;311:43;;;;;;367:13;:24;381:9;367:24;;;;;;;;;;;;;;;;;;;;;;;;;;;360:31;;235:161;;;:::o;546:224::-;610:4;626:6;635:1;626:10;;622:126;642:13;:20;;;;638:1;:24;622:126;;;701:9;681:29;;;:13;695:1;681:16;;;;;;;;;;;;;;;;;;;:29;;;;677:65;;;729:4;722:11;;;;677:65;664:3;;;;;;;622:126;;;760:5;753:12;;546:224;;;;;:::o;49:47::-;;;;;;;;;;;;;;;;;;;;;;:::o;106:30::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;400:142::-;495:4;466:33;;:25;481:9;466:14;:25::i;:::-;:33;;;458:43;;;;;;536:1;508:13;:24;522:9;508:24;;;;;;;;;;;;;;;;;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;400:142;:::o' } },
  sourceList: [ '' ],
  sources: { '': { AST: [Object] } } }
>  abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface)
[ { constant: true,
    inputs: [ [Object] ],
    name: 'totalVotesFor',
    outputs: [ [Object] ],
    payable: false,
    stateMutability: 'view',
    type: 'function' },
  { constant: true,
    inputs: [ [Object] ],
    name: 'validCandidate',
    outputs: [ [Object] ],
    payable: false,
    stateMutability: 'view',
    type: 'function' },
  { constant: true,
    inputs: [ [Object] ],
    name: 'votesReceived',
    outputs: [ [Object] ],
    payable: false,
    stateMutability: 'view',
    type: 'function' },
  { constant: true,
    inputs: [ [Object] ],
    name: 'candidateList',
    outputs: [ [Object] ],
    payable: false,
    stateMutability: 'view',
    type: 'function' },
  { constant: false,
    inputs: [ [Object] ],
    name: 'voteForCandidate',
    outputs: [],
    payable: false,
    stateMutability: 'nonpayable',
    type: 'function' },
  { inputs: [ [Object] ],
    payable: false,
    stateMutability: 'nonpayable',
    type: 'constructor' } ]
>  VotingContract = web3.eth.contract(abiDefinition)
ContractFactory {
  eth:
   Eth {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     getBalance: { [Function: send] request: [Function: bound ], call: 'eth_getBalance' },
     getStorageAt: { [Function: send] request: [Function: bound ], call: 'eth_getStorageAt' },
     getCode: { [Function: send] request: [Function: bound ], call: 'eth_getCode' },
     getBlock: { [Function: send] request: [Function: bound ], call: [Function: blockCall] },
     getUncle: { [Function: send] request: [Function: bound ], call: [Function: uncleCall] },
     getCompilers: { [Function: send] request: [Function: bound ], call: 'eth_getCompilers' },
     getBlockTransactionCount:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: getBlockTransactionCountCall] },
     getBlockUncleCount:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: uncleCountCall] },
     getTransaction:
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionByHash' },
     getTransactionFromBlock:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: transactionFromBlockCall] },
     getTransactionReceipt:
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionReceipt' },
     getTransactionCount: { [Function: send] request: [Function: bound ], call: 'eth_getTransactionCount' },
     call: { [Function: send] request: [Function: bound ], call: 'eth_call' },
     estimateGas: { [Function: send] request: [Function: bound ], call: 'eth_estimateGas' },
     sendRawTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendRawTransaction' },
     signTransaction: { [Function: send] request: [Function: bound ], call: 'eth_signTransaction' },
     sendTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendTransaction' },
     sign: { [Function: send] request: [Function: bound ], call: 'eth_sign' },
     compile: { solidity: [Object], lll: [Object], serpent: [Object] },
     submitWork: { [Function: send] request: [Function: bound ], call: 'eth_submitWork' },
     getWork: { [Function: send] request: [Function: bound ], call: 'eth_getWork' },
     coinbase: [Getter],
     getCoinbase: { [Function: get] request: [Function: bound ] },
     mining: [Getter],
     getMining: { [Function: get] request: [Function: bound ] },
     hashrate: [Getter],
     getHashrate: { [Function: get] request: [Function: bound ] },
     syncing: [Getter],
     getSyncing: { [Function: get] request: [Function: bound ] },
     gasPrice: [Getter],
     getGasPrice: { [Function: get] request: [Function: bound ] },
     accounts: [Getter],
     getAccounts: { [Function: get] request: [Function: bound ] },
     blockNumber: [Getter],
     getBlockNumber: { [Function: get] request: [Function: bound ] },
     protocolVersion: [Getter],
     getProtocolVersion: { [Function: get] request: [Function: bound ] },
     iban:
      { [Function: Iban]
        fromAddress: [Function],
        fromBban: [Function],
        createIndirect: [Function],
        isValid: [Function] },
     sendIBANTransaction: [Function: bound transfer] },
  abi:
   [ { constant: true,
       inputs: [Array],
       name: 'totalVotesFor',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: true,
       inputs: [Array],
       name: 'validCandidate',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: true,
       inputs: [Array],
       name: 'votesReceived',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: true,
       inputs: [Array],
       name: 'candidateList',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: false,
       inputs: [Array],
       name: 'voteForCandidate',
       outputs: [],
       payable: false,
       stateMutability: 'nonpayable',
       type: 'function' },
     { inputs: [Array],
       payable: false,
       stateMutability: 'nonpayable',
       type: 'constructor' } ],
  new: { [Function] getData: [Function: bound ] } }
>  byteCode = compiledCode.contracts[':Voting'].bytecode
'6060604052341561000f57600080fd5b6040516103e23803806103e2833981016040528080518201919050508060019080519060200190610041929190610048565b50506100c0565b82805482825590600052602060002090810192821561008a579160200282015b82811115610089578251829060001916905591602001919060010190610068565b5b509050610097919061009b565b5090565b6100bd91905b808211156100b95760008160009055506001016100a1565b5090565b90565b610313806100cf6000396000f30060606040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632f265cf714610072578063392e6678146100b35780637021939f146100f2578063b13c744b14610133578063cc9ab26714610172575b600080fd5b341561007d57600080fd5b610097600480803560001916906020019091905050610199565b604051808260ff1660ff16815260200191505060405180910390f35b34156100be57600080fd5b6100d86004808035600019169060200190919050506101e2565b604051808215151515815260200191505060405180910390f35b34156100fd57600080fd5b610117600480803560001916906020019091905050610242565b604051808260ff1660ff16815260200191505060405180910390f35b341561013e57600080fd5b6101546004808035906020019091905050610262565b60405180826000191660001916815260200191505060405180910390f35b341561017d57600080fd5b610197600480803560001916906020019091905050610286565b005b6000600115156101a8836101e2565b15151415156101b357fe5b600080836000191660001916815260200190815260200160002060009054906101000a900460ff169050919050565b600080600090505b60018054905081101561023757826000191660018281548110151561020b57fe5b90600052602060002090015460001916141561022a576001915061023c565b80806001019150506101ea565b600091505b50919050565b60006020528060005260406000206000915054906101000a900460ff1681565b60018181548110151561027157fe5b90600052602060002090016000915090505481565b60011515610293826101e2565b151514151561029e57fe5b6001600080836000191660001916815260200190815260200160002060008282829054906101000a900460ff160192506101000a81548160ff021916908360ff160217905550505600a165627a7a72305820d656e68956e578363e4124e152b2a002428282cc8f56349a55e77a8e807086fc0029'
>  deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000})
eth_accounts
eth_sendTransaction

  Transaction: 0xb3a1840e41d64e9295d7409d61e5ab9d9ce30cdd85170c62d428b5a23bc1e022
  Contract created: 0x474b6b4047440822ce45e5bf1b7620827b9351cd
  Gas usage: 353912
  Block Number: 32
  Block Time: Wed Mar 07 2018 20:52:04 GMT+0800 (CST)

Contract {
  _eth:
   Eth {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     getBalance: { [Function: send] request: [Function: bound ], call: 'eth_getBalance' },
     getStorageAt: { [Function: send] request: [Function: bound ], call: 'eth_getStorageAt' },
     getCode: { [Function: send] request: [Function: bound ], call: 'eth_getCode' },
     getBlock: { [Function: send] request: [Function: bound ], call: [Function: blockCall] },
     getUncle: { [Function: send] request: [Function: bound ], call: [Function: uncleCall] },
     getCompilers: { [Function: send] request: [Function: bound ], call: 'eth_getCompilers' },
     getBlockTransactionCount:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: getBlockTransactionCountCall] },
     getBlockUncleCount:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: uncleCountCall] },
     getTransaction:
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionByHash' },
     getTransactionFromBlock:
      { [Function: send]
        request: [Function: bound ],
        call: [Function: transactionFromBlockCall] },
     getTransactionReceipt:
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionReceipt' },
     getTransactionCount: { [Function: send] request: [Function: bound ], call: 'eth_getTransactionCount' },
     call: { [Function: send] request: [Function: bound ], call: 'eth_call' },
     estimateGas: { [Function: send] request: [Function: bound ], call: 'eth_estimateGas' },
     sendRawTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendRawTransaction' },
     signTransaction: { [Function: send] request: [Function: bound ], call: 'eth_signTransaction' },
     sendTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendTransaction' },
     sign: { [Function: send] request: [Function: bound ], call: 'eth_sign' },
     compile: { solidity: [Object], lll: [Object], serpent: [Object] },
     submitWork: { [Function: send] request: [Function: bound ], call: 'eth_submitWork' },
     getWork: { [Function: send] request: [Function: bound ], call: 'eth_getWork' },
     coinbase: [Getter],
     getCoinbase: { [Function: get] request: [Function: bound ] },
     mining: [Getter],
     getMining: { [Function: get] request: [Function: bound ] },
     hashrate: [Getter],
     getHashrate: { [Function: get] request: [Function: bound ] },
     syncing: [Getter],
     getSyncing: { [Function: get] request: [Function: bound ] },
     gasPrice: [Getter],
     getGasPrice: { [Function: get] request: [Function: bound ] },
     accounts: [Getter],
     getAccounts: { [Function: get] request: [Function: bound ] },
     blockNumber: [Getter],
     getBlockNumber: { [Function: get] request: [Function: bound ] },
     protocolVersion: [Getter],
     getProtocolVersion: { [Function: get] request: [Function: bound ] },
     iban:
      { [Function: Iban]
        fromAddress: [Function],
        fromBban: [Function],
        createIndirect: [Function],
        isValid: [Function] },
     sendIBANTransaction: [Function: bound transfer] },
  transactionHash: '0xb3a1840e41d64e9295d7409d61e5ab9d9ce30cdd85170c62d428b5a23bc1e022',
  address: undefined,
  abi:
   [ { constant: true,
       inputs: [Array],
       name: 'totalVotesFor',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: true,
       inputs: [Array],
       name: 'validCandidate',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: true,
       inputs: [Array],
       name: 'votesReceived',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: true,
       inputs: [Array],
       name: 'candidateList',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: false,
       inputs: [Array],
       name: 'voteForCandidate',
       outputs: [],
       payable: false,
       stateMutability: 'nonpayable',
       type: 'function' },
     { inputs: [Array],
       payable: false,
       stateMutability: 'nonpayable',
       type: 'constructor' } ] }
  • 合约地址
    其中 Contract created: 0x474b6b4047440822ce45e5bf1b7620827b9351cd 就是合约的地址这个保存下接下来在index.js文件里传入这个合约地址
    image.png

    `

区块链技术交流

image.png