In me the tiger sniffs the rose.
心有猛虎,细嗅蔷薇
在以太坊的共有链上部署智能合约、发起交易需要花费以太币。而通过修改配置,可以在本机搭建一套以太坊私有链,因为与公有链没关系,既不用同步公有链庞大的数据,也不用花钱购买以太币,很好地满足了智能合约开发和测试的要求,开发好的智能合约也可以很容易地切换接口部署到以太坊公有链上。
打开终端执行下面的命令
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
macdeiMac:Downloads mac$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
==> This script will install: /usr/local/bin/brew
/usr/local/share/doc/homebrew
/usr/local/share/man/man1/brew.1
/usr/local/share/zsh/site-functions/_brew
/usr/local/etc/bash_completion.d/brew
/usr/local/Homebrew
==> The Xcode Command Line Tools will be installed.
Press RETURN to continue or any other key to abort
==> Searching online for the Command Line Tools ==> /usr/bin/sudo /usr/bin/touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress Password:
==> Installing Command Line Tools (macOS High Sierra version 10.13) for Xcode-9.4 ==> /usr/bin/sudo /usr/sbin/softwareupdate -i Command\ Line\ Tools\ (macOS\ High\ Sierra\ version\ 10.13)\ for\ Xcode-9.4 Software Update Tool
Downloading Command Line Tools (macOS High Sierra version 10.13) for Xcode
Downloaded Command Line Tools (macOS High Sierra version 10.13) for Xcode
Installing Command Line Tools (macOS High Sierra version 10.13) for Xcode
Done with Command Line Tools (macOS High Sierra version 10.13) for Xcode
Done.
==> /usr/bin/sudo /bin/rm -f /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress Password:
Sorry, try again.
Password:
==> /usr/bin/sudo /usr/bin/xcode-select --switch /Library/Developer/CommandLineTools ==> Downloading and installing Homebrew... HEAD is now at 9777b278 Merge pull request #4810 from MikeMcQuaid/mojave-mmacosx-version-min
==> Homebrew is run entirely by unpaid volunteers. Please consider donating: https://github.com/Homebrew/brew#donations
==> Migrating /Library/Caches/Homebrew to /Users/mac/Library/Caches/Homebrew... ==> Deleting /Library/Caches/Homebrew... Already up-to-date.
==> Installation successful!
==> Homebrew has enabled anonymous aggregate formulae and cask analytics. Read the analytics documentation (and how to opt-out) here:
https://docs.brew.sh/Analytics.html
==> Homebrew is run entirely by unpaid volunteers. Please consider donating: https://github.com/Homebrew/brew#donations
==> Next steps: - Run `brew help` to get started - Further documentation: https://docs.brew.sh
brew install go
macdeiMac:Downloads mac$ brew install go
Updating Homebrew...
==> Downloading https://homebrew.bintray.com/bottles/go-1.11.high_sierra.bottle.
######################################################################## 100.0%
==> Pouring go-1.11.high_sierra.bottle.tar.gz ==> Caveats
A valid GOPATH is required to use the `go get` command.
If $GOPATH is not specified, $HOME/go will be used by default:
https://golang.org/doc/code.html#GOPATH
You may wish to add the GOROOT-based install location to your PATH:
export PATH=$PATH:/usr/local/opt/go/libexec/bin ==> Summary
�� /usr/local/Cellar/go/1.11: 9,273 files, 403.9MB
macdeiMac:Downloads mac$
macdeiMac:Downloads mac$ cd go-ethereum-1.5.9
macdeiMac:go-ethereum-1.5.9 mac$ pwd
/Users/mac/Downloads/go-ethereum-1.5.9
macdeiMac:go-ethereum-1.5.9 mac$ make geth
brew install solidity
macdeiMac:go-ethereum-1.5.9 mac$ cd /Users/mac/Desktop/GitHub/Solidity/learn
macdeiMac:learn mac$ mkdir privatechain
macdeiMac:learn mac$ pwd
/Users/mac/Desktop/GitHub/Solidity/learn
macdeiMac:learn mac$ ls
BLC attributesMethod.sol method.sol
Person.sol attributesaccess.sol method1.sol
SmartContractDemo inherit.sol privatechain
macdeiMac:learn mac$
geth
来加载geth --networkid 123 --dev --datadir data1 --rpc --rpcaddr 192.168.1.5 --rpcport 8989 --port 3000
各选项含义如下:
–identity
:指定节点 ID;
–rpc
:表示开启 HTTP-RPC 服务;
–rpcaddr
:HTTP-RPC 服务ip地址;
–rpcport
:指定 HTTP-RPC 服务监听端口号(默认为 8545);
–datadir
:指定区块链数据的存储位置;
–port
:指定和其他节点连接所用的端口号(默认为 30303);
–nodiscover
:关闭节点发现机制,防止加入有同样初始配置的陌生节点。
如果你切换到data1
文件夹里面,你会看到geth
, geth.ipc
, 和 keystore
。
geth attach ipc:/Users/mac/Desktop/GitHub/Solidity/learn/privatechain/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.7.1-stable-05101641/darwin-amd64/go1.9.1
modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0
这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:
eth
:包含一些跟操作区块链相关的方法;
net
:包含一些查看p2p网络状态的方法;
admin
:包含一些与管理节点相关的方法;
miner
:包含启动&停止挖矿的一些方法;
personal
:主要包含一些管理账户的方法;
txpool
:包含一些查看交易内存池的方法;
web3
:包含了以上对象,还包含一些单位换算的方法。
查看账户
> personal.listAccounts
[]
>
创建账户
> personal.newAccount('wt')
"0xb6d7d842e7dc9016fa6900a183b2be26fc90b2d8"
>
PS:里面的wt是你账户的密码,输入你自己喜欢的密码。
查看账户
> personal.listAccounts
["0xb6d7d842e7dc9016fa6900a183b2be26fc90b2d8"]
>
> web3.eth.coinbase
"0xb6d7d842e7dc9016fa6900a183b2be26fc90b2d8"
>
pragma solidity ^0.4.4;
contract test {
function multiply(uint a) returns(uint d){
return a * 7;
}
}
6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029
[
{
"constant": true,
"inputs": [ { "name": "a", "type": "uint256" } ],
"name": "multiply",
"outputs": [ { "name": "d", "type": "uint256" } ],
"payable": false,
"type": "function",
"stateMutability": "view" }
]
[{\"constant\":true,\"inputs\":[{\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"multiply\",\"outputs\":[{\"name\":\"d\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\",\"stateMutability\":\"view\"}]
> var abi = JSON.parse('[{\"constant\":true,\"inputs\":[{\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"multiply\",\"outputs\":[{\"name\":\"d\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\",\"stateMutability\":\"view\"}]')
> myContract = web3.eth.contract(abi)
{
abi: [{
constant: false,
inputs: [{...}],
name: "multiply",
outputs: [{...}],
payable: false,
type: "function"
}],
eth: {
accounts: ["0x2abf46d8b0d940cdeedd55872bc0648add40227d"],
blockNumber: 384,
coinbase: "0x2abf46d8b0d940cdeedd55872bc0648add40227d",
compile: {
lll: function(),
serpent: function(),
solidity: function()
},
defaultAccount: undefined,
defaultBlock: "latest",
gasPrice: 0,
hashrate: 0,
mining: false,
pendingTransactions: [],
protocolVersion: "0x3f",
syncing: false,
call: function(),
contract: function(abi),
estimateGas: function(),
filter: function(fil, callback),
getAccounts: function(callback),
getBalance: function(),
getBlock: function(),
getBlockNumber: function(callback),
getBlockTransactionCount: function(),
getBlockUncleCount: function(),
getCode: function(),
getCoinbase: function(callback),
getCompilers: function(),
getGasPrice: function(callback),
getHashrate: function(callback),
getMining: function(callback),
getPendingTransactions: function(callback),
getProtocolVersion: function(callback),
getRawTransaction: function(),
getRawTransactionFromBlock: function(),
getStorageAt: function(),
getSyncing: function(callback),
getTransaction: function(),
getTransactionCount: function(),
getTransactionFromBlock: function(),
getTransactionReceipt: function(),
getUncle: function(),
getWork: function(),
iban: function(iban),
icapNamereg: function(),
isSyncing: function(callback),
namereg: function(),
resend: function(),
sendIBANTransaction: function(),
sendRawTransaction: function(),
sendTransaction: function(),
sign: function(),
signTransaction: function(),
submitTransaction: function(),
submitWork: function()
},
at: function(address, callback),
getData: function(),
new: function()
}
> account1 = web3.eth.coinbase
"0x2abf46d8b0d940cdeedd55872bc0648add40227d"
> web3.eth.getBalance(account1)
0
>
如果余额大于0,继续,否则,开始挖矿。
> miner.start();
null
>
miner.stop();
> miner.start();
null
> miner.stop();
true
> web3.eth.getBalance(account1)
1.152e+21
>
wt
: 换成你的密码。
> personal.unlockAccount(account1, 'wt')
true
>
> bytecode = "6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
"6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
> web3.eth.estimateGas({data: bytecode})
Error: invalid argument 0: json: cannot unmarshal hex string without 0x prefix into Go struct field CallArgs.data of type hexutil.Bytes
at web3.js:3104:20
at web3.js:6191:15
at web3.js:5004:36
at <anonymous>:1:1
> bytecode = "0x6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
"0x6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
> web3.eth.estimateGas({data: bytecode})
98391
>
备注:字节码前面需要添加0x
。手续费大概为98391gas
。
> contractInstance = myContract.new({data: bytecode gas: 1000000, from: account1}, function(e, contract){
if(!e){
if(!contract.address){
console.log("Contract transaction send: Transaction Hash: "+contract.transactionHash+" waiting to be mined...");
}else{
console.log("Contract mined! Address: "+contract.address);
console.log(contract);
}
}else{
console.log(e)
}
})
Contract transaction send: Transaction Hash: 0x5e2aebbf400d71a32e807dc3f11f1053b6ee3b2a81435ed8ace2fa54eebb9f3d waiting to be mined...
{
abi: [{
constant: false,
inputs: [{...}],
name: "multiply",
outputs: [{...}],
payable: false,
type: "function"
}],
address: undefined,
transactionHash: "0x5e2aebbf400d71a32e807dc3f11f1053b6ee3b2a81435ed8ace2fa54eebb9f3d"
}
>
> miner.start()
null
> Contract mined! Address: 0xbf8b24283f2516360d3a4ba1db0df78ae74689db
[object Object]
> miner.stop()
true
>
> eth.getCode(contractInstance.address)
"0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
>
> contractInstance.multiply(6)
42
>