如何使用web3.js 部署智能合约
来源:互联网 发布:linux rsysnc 编辑:程序博客网 时间:2024/06/05 04:42
在编译之前,需要安装node以及npm,之后需要建立一个文件夹,使用以下指令
$ mkdir web3test && cd web3test$ npm init$npm install web3 --save
Enter Solidity.
In a nutshell, Solidity ( check for the correct docs version !) is the language in which you write contracts, it’s syntax is similar to javascript (importantly it is statically typed and supports libraries and other cool features). So the plan is to write a contract, then compile it and then release/interact with it through web3.js which we briefly covered in the last part of this series. So let’s start with a very very simple contract.
pragma solidity ^0.4.0;contract HelloWorldContract { function sayHi() constant returns (string){ return 'Hello World'; }}
While it might look simple, there is a lot going on here, so let’s comment this example:
// You will also need a solidity linter for ATOM ! like linter-solidity// FILE : HelloWorldContract.sol// Notice the .sol (for solidity) extension.pragma solidity ^0.4.0;// will not compile with a compiler earlier than version 0.4.0contract HelloWorldContract {// notice the word contract function sayHi() constant returns (string){// As a typed language, this function specifies what it returns via the constant returns (string) bit. return 'Hello World'; }}
This contract should respond with “Hellow World” when called (we’ll look into that later) via the sayHi() function.
Compiling :
As mentioned, in order to make contracts work, we first need to compile them and then release or deploy them into the network, the first thing we will need to compile is the solc ( solidity ) node package: npm install solc
And now in atom we actually do the compiling:
以下所有的js文件都需要在一个终端运行命令行:eth -j -admin-via-http
,否则会出现各种错误。
// FILE: compile.js const fs = require ('fs');const solc = require ('solc');const input = fs.readFileSync('HelloWorldContract.sol');const output = solc.compile(input.toString(), 1);for (var contractName in output.contracts){ console.log(contractName + ': ' + output.contracts[contractName].bytecode)}// :helloWorldContract: 6060604052341561000f57600080fd5b5b6101488061001f6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630c49c36c811461003d575b600080fd5b341561004857600080fd5b6100506100c8565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561008d5780820151818401525b602001610074565b50505050905090810190601f1680156100ba5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100d061010a565b60408051908101604052600b81527f48656c6c6f20576f726c64000000000000000000000000000000000000000000602082015290505b90565b602060405190810160405260008152905600a165627a7a72305820db2690e18e82d5fc2cb625d3b4d4a0a8d9abbdd5df5e343e091d6bf3ed3a2e5a0029
Success ! the weird looking block at the bottom is our compiled contract ( Ethereum-specific binary format or bytecode ), we now need to deploy it to the blockchain and then interact with it:
pre - Deploying :
In order to deploy our contract we first need to create a contract object in web3, in order to do that we need to format those numbers up there into an Ethereum contract ABI ( Application Binary Interface) Array :
// FILE: compileDeploy.jsconst fs = require ('fs');const solc = require ('solc');const Web3 = require ('web3');const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));const input = fs.readFileSync('HelloWorldContract.sol');const output = solc.compile(input.toString(), 1);const bytecode = output.contracts[':helloWorldContract'].bytecode;const abi = output.contracts[':helloWorldContract'].interface;const helloWorldContract = web3.eth.contract(JSON.parse(abi));console.log(helloWorldContract); // contract structure...
An ABI in case you were wondering“ it’s basically how you can encode solidity contracts for the EVM and backwards how to read the data out of transactions as well as contract to contract communication.” Neat
Deploying
// FILE: compileDeploy.jsconsole.log('Setting up...');const fs = require ('fs');const solc = require ('solc');const Web3 = require ('web3');const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));console.log('Reading Contract...');const input = fs.readFileSync('HelloWorldContract.sol');console.log('Compiling Contract...');const output = solc.compile(input.toString(), 1);const bytecode = output.contracts[':helloWorldContract'].bytecode;const abi = output.contracts[':helloWorldContract'].interface;//Contract Objectconst helloWorldContract = web3.eth.contract(JSON.parse(abi));console.log('unlocking Coinbase account');const password = "账户密码";try { web3.personal.unlockAccount(自己的账户名称, password,100);} catch(e) { console.log(e); return;}console.log("Deploying the contract");const helloWorldContractInstance = helloWorldContract.new({ data: '0x' + bytecode, from: 账户名称, gas: 1000000}, (err, res) => { if (err) { console.log(err); return; } console.log(res.transactionHash); // If we have an address property, the contract was deployed if (res.address) { console.log('Contract address: ' + res.address); }});
And the Readout:
Setting up...Reading Contract...Compiling Contract...unlocking Coinbase accountDeploying the contract0x876453431987c163b84153e99ec8f6f7a7bd232bb41dfe0537884907d77696640x876453431987c163b84153e99ec8f6f7a7bd232bb41dfe0537884907d7769664Contract address: 0x2759054bbfbaed66319ecbce83824efce04ee63c
What just happened ?
In Ethereum, a contract is created by sending a transaction (from an address you control - hence the unlock part), the payload of this transaction ( which has to be formatted accordingly — hence the contractInstance part) is the contract code which now lives on the blockchain and has an address, let’s query our trusty block explorer (etherscan.io) and see what it tells us:
Beyond the obvious observation that it exists and was identified as a contract , there is a TxHash and a Contract Creator Address ( along with the Contract Address ) that is now part of the blockchains history; and if you click on the Contract Code tab ?
You will get the exact compiled contract we started with, an instance of which now lives on the blockchain and is ready for us to interact with ! ( scroll up to the :helloworld code comment, it’s the same code plus the 0x bit ).
A note about costs: Even though we are on a testnet where the Ether is free, it should be noted that this transaction incurred in some costs and there is a complexity associated with them in the form of gas, gas prices and gas limits which I will sidestep for now, just be mindful they exist and where covered by the gas: 1000000 line while deploying.
Interacting with the contract…
So now that our smart contract has been created and deployed, our last task will be to interact with it, if you remember our contract has one function:
function sayHi() constant returns (string){ return 'Hello World'; }
Which if we are successful will somehow return the words “Hello World”, well that’s the plan anyways.
Inspecting our contract via web3:
Now that our contract lives in the blockchain, we can query the blockchain for our contracts code like so:
console.log('Setting up...');const solc = require ('solc');const Web3 = require ('web3');const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));console.log('Reading contract...');const deployedHelloWorldContractInstance = web3.eth.getCode("0x2759054bbfbaed66319ecbce83824efce04ee63c");console.log('Contract Code: ' + deployedHelloWorldContractInstance);
And our readout:
Setting up...Reading contract...Contract Code: 0x606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630c49c36c811461003d575b600080fd5b341561004857600080fd5b6100506100c8565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561008d5780820151818401525b602001610074565b50505050905090810190601f1680156100ba5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100d061010a565b60408051908101604052600b81527f48656c6c6f20576f726c64000000000000000000000000000000000000000000602082015290505b90565b602060405190810160405260008152905600a165627a7a72305820db2690e18e82d5fc2cb625d3b4d4a0a8d9abbdd5df5e343e091d6bf3ed3a2e5a0029
Which surprise surprise is still the same code we added to our hello world contract.
Gotcha time: Now in order to call our method: sayHi() we need to instantiate a contract, the gotcha is that we need an ABI to do so, and the original maker of the contract (that’s us) needs to make it available, so we need to rewrite our original contract code (compileDeploy.js ) so we can write our ABI and then read it in json format, for clarity sake here’s a script that takes care of the writing part ,you can merge it with the compileDeploy one:
// FILE: exportABI.jsconsole.log('Setting up...');const fs = require ('fs');const solc = require ('solc');const Web3 = require ('web3');console.log('Reading Contract...');const input = fs.readFileSync('HelloWorldContract.sol');console.log('Compiling Contract...');const output = solc.compile(input.toString(), 1);const bytecode = output.contracts[':HelloWorldContract'].bytecode;console.log('Generating ABI...');const abi = output.contracts[':HelloWorldContract'].interface;fs.writeFile("./HelloWorldABI.JSON", abi, function(err) { if(err) { return console.log(err); }console.log("ABI Saved");});
Resulting in the following HelloWorldABI.json:
[{"constant":true,"inputs":[],"name":"sayHi","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]
Back to calling our method:
let’s try instantiating a contract by joining these 2 parts ( the abi and the contract code):
FILE: callContract.jsconsole.log('Setting up...');const solc = require ('solc');const Web3 = require ('web3');console.log('Reading abi');const HelloWorldABI = require("./HelloWorldABI.json");console.log('Connecting');const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));const helloWorldContract = web3.eth.contract(HelloWorldABI);var helloWorldContractInstance = helloWorldContract.at("0x2759054bbfbaed66319ecbce83824efce04ee63c");console.log(helloWorldContractInstance);
And our resulting instance contract code:
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: null, address: '0x2759054bbfbaed66319ecbce83824efce04ee63c', abi: [ { constant: true, inputs: [], name: 'sayHi', outputs: [Array], payable: false, stateMutability: 'view', type: 'function' } ], sayHi: { [Function: bound ] request: [Function: bound ], call: [Function: bound ], sendTransaction: [Function: bound ], estimateGas: [Function: bound ], getData: [Function: bound ], '': [Circular] }, allEvents: [Function: bound ] }
You can ignore most of it for now, but notice that our contract now has our method definition: sayHi provided by the abi we just read, so we are ready to call our function, but before so let’s talk about the ways we can call contract functions in the Ethereum Network :
A tale of two (2) calls :
In order to finally call our sayHi() function, we need to be aware that there are 2 ways of interacting with a contract:
1、Call a ‘dry run’ which happens in your computer and has no effects on the blockchain contract ( it doesn’t change it’s state ) or has costs beyond initial deployment :
console.log('Setting up...');const solc = require ('solc');const Web3 = require ('web3');console.log('Reading abi');const HelloWorldABI = require("./HelloWorldABI.json");console.log('Connecting');const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));console.log('Creating contract instance');const helloWorldContract = web3.eth.contract(HelloWorldABI);var helloWorldContractInstance = helloWorldContract.at("0x2759054bbfbaed66319ecbce83824efce04ee63c");console.log ('calling the contract locally');console.log(helloWorldContractInstance.sayHi.call());
And our readout:
Setting up...Reading abiConnectingCreating contract instanceCalling the contract locallyHello World // Finally !
2.- sendTransaction Contracts can receive transactions along with values/parameters (which I am skipping for now) and these transactions in turn are the only ones that can affect the state of the contract, they also cost gas, here’s an example although since our contract has no state or state changing functions it does nothing, yet costs us ether.
console.log('Setting up...');const solc = require ('solc');const Web3 = require ('web3');console.log('Reading abi');const HelloWorldABI = require("./HelloWorldABI.json");console.log('Connecting');const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));console.log('Creating contract instance');const helloWorldContract = web3.eth.contract(HelloWorldABI);var helloWorldContractInstance = helloWorldContract.at("0x2759054bbfbaed66319ecbce83824efce04ee63c");console.log('unlocking Coinbase account');const password = "yourPassword";try { web3.personal.unlockAccount(web3.eth.coinbase, password);} catch(e) { console.log(e); return;}console.log ('sending Transaction to the contract');helloWorldContractInstance.sayHi.sendTransaction({from:web3.eth.coinbase}, function(err, txHash) { if (err != null) { console.error("Error while sending transaction: " + err); } else{ console.log("Transaction Sent here's you txHash: " + txHash); }});
And our readout:
Setting up...Reading abiConnectingCreating contract instanceunlocking Coinbase accountsending Transaction to the contractTransaction Sent here's you txHash: 0x0750fdf4e24055aa4f73bd25e06ba19fa73111f3925d2108422e47bebd01d12a
The main difference with call, is that the transaction does not return a value, and it is not processed immediately, instead we get a txHash you can check on the block explorer :
And in parity UI :
This last type of way of interacting with a contract is perhaps the most challenging and rewarding and we will dive into it in the next part before tackling tokens, but for now let’s take a breath and recap what we have so far covered:
Notes Part 1 : Setting up : Getting a wallet/client , connecting to a test ethereum blockchain and getting some test ether.
Notes Part 2: web3.js/node : Interacting with the blockchain through web3.js and node for more convenience and to ease development.
Notes Part 3: Solidity ( this post ) :Installing solidity (Ethereums contract writing language ) , Creating a very basic contract, compiling it, deploying it to the blockchain ( the test one) and interacting with it.
If this information was valuable to you, please consider donating to the following addresses:
Bitcoin: 1KBGyZW1raxCCLZgfXexeYwJZxtdLnUG6d
Ether: 0xD9E724BFb376F1AbDb30382D1923eA8aD1eD22c4
Cheers !
Keno
About the Author :
Born Eugenio Noyola Leon (Keno) I am a Designer,Web Developer/programmer, Artist and Inventor, currently living in Mexico City, you can find me at www.k3no.com
- 如何使用web3.js 部署智能合约
- web3.js与合约交互
- 如何开发编译部署调用智能合约
- 手把手教你搭建智能合约测试环境、开发、编译、部署以及如何通过JS调用合约方法
- truffle部署智能合约
- geth1.6部署智能合约
- 智能合约部署及调用
- 以太坊之部署智能合约
- 以太坊智能合约部署与交互
- 将智能合约部署到私有链
- 区块链智能合约部署初探
- 使用 Browser-solidity 在 Go-Ethereum1.7.2 上进行简单的智能合约部署
- Truffle 3.0部署智能合约至Ethereum节点(区别truffle部署智能合约到testrpc)
- 如何写安全的智能合约
- 智能合约
- 如何使用数字货币开发工具来做智能合约的测试驱动开发
- 如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App,decentralization Voting Dapp
- 如何在私有区块链上编写、部署以及与以太坊进行交互的智能合约
- 常见的代码性能优化
- 网易面试题引发的思考
- EasyNVR RTSP转RTMP-HLS流媒体服务器前端构建之:关于接口调用常见的一些问题(401 Unauthorized)
- JavaScript 内存泄漏教程
- Intent简介及属性
- 如何使用web3.js 部署智能合约
- 图说Java —— 理解Java机制最受欢迎的8幅图
- LeetCode算法题——Wildcard Matching
- JavaScript ES6中export及export default的区别
- Server Tomcatv8.5 Server at localhost failed to start
- Chrome开发工具窗口使用记录
- pillow.Image.open() 对某些jpg文件报OSError
- 七牛云查看音视频资源的元信息-avinfo
- C语言 位域