Geth_搭建私有链

MetaMask_pass:spot raccoon network sweet feel song knee put just uncover news audit //我的MetaMask助记词 ;可以直接用Remix-IDE连接geth,也可以通过MetaMask连接Geth,这样MetaMask帮助你实现r s v ,不用自己去弄!

Geth客户端:Geth_download

Part0 MetaMask

1

1
2
#通过MetaMask连接本地Geth或者Ganache搭建的私有链或者TestRPC等都可以,这样会比较方便查看部署的合约和交易信息,而且更贴合实际操作。
#如果不想搭建私有链,可以通过测试网络去部署合约和交易也是可以的,但是首先需要从对应的测试网络水龙头获取ether操作及之后测试需要科学上网。
  • 在本地通过npm安装一个remixd,这样可以实时将本地和浏览器代码同步,方便存储代码。npm install remixd -g

    2

  • 部署合约和测试合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#智能合约
#Solidity编译器是solc,通过remix-ide编写合约时候,注意solc的版本
#pragma solidity >0.6.2 也可以,当版本出现错误时候,可以尝试改变编译版本
pragma solidity ^0.6.2;

contract Test{
//contract balance
uint public money ;
//在remix中修改value 运行paly,金额就转到合约当中去了,然后通过transfer转到其他账户中去
function paly() public payable{
money = msg.value;
}

//contract balance
function getBalance() public view returns(uint256){
return address(this).balance;
}

address payable addr = 0x78662A9CFfFc852cF61a5c6c637cFB93f1c59397;
//transfer who ,who call
function transfer(uint i ) public payable {
addr.transfer ( i * 10 ** 18);
}
}
  • 接种编写合约的方式

    • VS code IDE,代码编写,基本的语法检查.
    • Remix IDE,简单代码编译运行看结果.方便学习.
    • Truffle 环境,生产环境,较为复杂的代码编译部署.
  • ENVIRONMENT

    • JavaScriptVM
      • 该方式环境是将合约部署到浏览器的Solidity编译环境,可以在内存中模拟合约,直接运行,而不需要部署等复杂流程,适合入门学习.
    • Injected Web3
      • 该方式可以连接到MetaMask.
    • Web3 Provider
      • 该方式通过本地私有网络的rpc端口,链接到本地私有网络进行调试.
  • Deployed Contracts

    • 可以看到已经部署的合约,此时就可以看到在合约中写的相应get-set函数和public的状态变量;
    • 可以进行智能合约回调,当且只有产生新的数据才会发生交易,否则仅仅是调用,而不会产生新的交易区块.

3

Part1 Geth入门

  • 创世块
1
2
3
4
5
6
7
8
9
10
11
{
"config": {
"chainId": 15
},
"difficulty": "2000",
"gasLimit": "2100000",
"alloc": {
"7df9a875a174b3bc565e6424a0050ebc1b2d1d82": { "balance": "300000000000000000000" },
"f41c74c9ae680c1aa78f42e5647a62f353b7bdde": { "balance": "400000000000000000000" }
}
}
  • 初始化创世快
1
2
3
D:\gethData>geth --datadir . init genesis.json
此时在testGeth目录下会生成data目录,data目录又包含geth和keystore目录,geth目录存储区块数据,keystore目录则保存账户信息。
--init #根据genesis.json文件初始化创世区块
  • 启动geth并开启远程RPC然后log输出到output.log里面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
D:\gethData>geth --datadir ./data0/ --rpc --rpccorsdomain "*" --rpcaddr "0.0.0.0" --rpcapi "personal,admin,miner,db,eth,net,web3" --ipcdisable  --nodiscover  --allow-insecure-unlock --networkid 15 console 2>> output.log
D:\gethData>geth --datadir "./data0/" --nodiscover --ipcdisable --port 3333 --rpc --rpcport 4444 --rpcapi="db,eth,net,web3,personal" --allow-insecure-unlock --rpccorsdomain="http://remix.ethereum.org" --networkid 1314 console 2>output.log
--datadir #指定数据存储位置(也是默认的私钥仓库位置keystore)
--networkid 123#参数表示区块链网络ID标识,
--console #参数表示进入geth控制台。
--rpc #启动HTTP-RPC服务(基于HTTP的)
--rpcapi #远程可调用的功能,默认web3,net,eth。4.24版本必须添加personal,否则remix无法读取本地账户列表;4.24版本testrpc也是无法读取用户列表。
--rpccorsdomain #指定一个可以接收请求来源的以逗号间隔的域名列表(浏览器访问的话,要强制指定该选项)
--rpcaddr # HTTP-RPC服务器监听地址(default: "localhost")
--rpcport "8545" #设置geth的端口号,默认为8545
--port "30303" #设置监听端口号,用于与其他按节点进行连接,默认30303
--identity "TestNetMainNode" #设置节点标识
--ipcdiscover #关闭进程间通信
--maxpeers 0 #设置网络中可以被接入的最大节点数目,0代表不被其他节点接入
--nodiscover #私有链,不被别人添加
--allow-insecure-unlock #禁止了HTTP通道解锁账户
--2>> output.log #错误追加输出到output.log(所有信息不管错误和正确都输出到文件中)
#连接测试网进入控制台,此时我们已经进入geth测试网的交互式控制台,窗口也显示「Welcome to the Geth JavaScript console」成功提示!
#注意:
#https://blog.csdn.net/qq_32938169 #某位大佬博客
#在当前目录下运行 geth,就会启动这条私链,注意要将 networked 设置为与创世块配置里的chainId 一致。
#异常:使用最新版本geth客户,当执行personal.unlockAccount()或在程序中调用personal_unlockAccount接口时,会出现:account unlock with HTTP access is forbidden异常。
#异常原因:新版本geth,出于安全考虑,默认禁止了HTTP通道解锁账户,相关issue:https://github.com/ethereum/go-ethereum/pull/17037
  • 发送一比交易:
1
personal.sendTransaction({from: "0xaC58C330aC8fF04fF828684d3FFABEFE987de7cb" , to: eth.accounts[0] , value: web3.toWei(100 , "ether")})
  • 查询账户余额且以ether方式显示
1
web3.fromWei(eth.getBalance("0xaC58C330aC8fF04fF828684d3FFABEFE987de7cb"),,'ether')
  • 查询账户列表
1
2
3
eth.accounts  #数组
- 输出结果:[]
- 含义:意思是无账户地址,因为我们什么也没做,所以当然是不会凭空出现账户了。
  • 创建新账户
1
2
3
personal.newAccount("password")
# 输出结果:hash
# 含义:表明账户新建成功,返回账户地址,123为账户密码。此时我们再次查询账户列表会发现已有刚创建的地址了。
  • 查询账户余额
1
2
3
eth.getBalance(eth.accounts[0])
# 输出结果:0
# 含义:表明这个账户的余额是0。
  • 启动或停止挖矿
1
2
3
miner.start();#开始挖矿
admin.sleepBlocks(1);
miner.stop()
  • 以Ether显示余额
1
web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")#查询余额

  • 常见对象
1
2
3
4
5
6
7
8
Geth Console 是一个交互式的 JavaScript 执行环境,里面内置了一些用来操作以太坊的 JavaScript 对象,我们可以直接调用这些对象来获取区块链上的相关信息。这些对象主要包括:
eth#主要包含对区块链进行访问和交互相关的方法;
net#主要包含查看 p2p 网络状态的方法;
admin#主要包含与管理节点相关的方法;
miner# 主要包含挖矿相关的一些方法;
personal#包含账户管理的方法;
txpool#包含查看交易内存池的方法;
web3#包含以上所有对象,还包含一些通用方法。
  • 常用命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#分类展示常见命令:
Personal:
personal.newAccount("password")#创建账户;
personal.unlockAccount(eth.accounts[0])#解锁账户0;
personal.unlockAccount(eth.coinbase)#解锁当前挖矿的账户
personal.sendTransaction() #发送交易;参数:from to value
Eth:
eth.accounts #数组;列出系统中的账户;
eth.getBalance()#查看账户余额,返回值的单位是 Wei;
eth.blockNumber#列出当前区块高度;
eth.getTransaction()#获取交易信息;
eth.getBlock()#获取区块信息;
eth.estimateGas({data: code})#估计部署合约要用的gas
eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(2)})#交易
//部署合约
var code ="合约bytecode";
var abi = "合约ABI";
var myContract = eth.contract(abi) #创建类,合约的ABI
myContract.new({from:eth.accounts[0] , data:code , gas:210000})#创建合约实例
Miner:
miner.start()#开始挖矿;默认线程12
miner.stop()#停止挖矿;
miner.setEtherbase(eth.accounts[0])#设置挖矿人
Web3:
web3.fromWei()# Wei 换算成以太币;
web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')#以ether方式查看余额
web3.toWei()#以太币换算成 Wei;
Txpool:
txpool.status#交易池中的状态;
  • 既然是javaScript的执行环境,肯定可以定义一些变量等其他
1
2
#定义变量
var variablename = value;

Part2 部署智能合约

  • 在Remix-IDE中,可可以在编译界面看到
    • Compilation Details
      • 打开可以看到ABI(Json还要进行压缩转移麻烦)和ByteCode(也可以直接支付下方的)
      • 更重要的是,可以直接复制WEB3DEPLOY的给定的JavaScript脚本直接粘贴到Geth即可,方便快捷
      • 惭愧:上面两种方式我都失败了,懒得弄了,后续有需求在搞,网上教程找个很多,都是这样操作的,但是我就是不成功,最后乖乖的直接部署到Ganache/TestRPC。
    • IPFS,星际文件系统(分布式文件系统,去中心化,底层区块链)内容很多,功能很强大.Download科学上网去下,或者Git
      • 我目前知道的好处:比如,互联网中常见的html网页,很多都是重复的内容,但是存储多份;此时如果通过IPFS进行存储,由于IPFS是基于内容寻址的,所以只要内容一样,解析的地址是同一个
      • 其次就是,IPDS也可以解决记录多版本问题

4

  • 定义变量存储合约信息
1
2
var code ="合约bytecode";
var abi = "合约ABI";
  • 估算部署合约要用的gas
1
eth.estimateGas({data: code})
  • 部署合约
1
2
3
4
var myContract = eth.contract(abi)
//创建类
var contract1 =myContract.new({from:"0xe473d288faf6c2d1812dbb759d7423605c7d1a58",data:code,gas:1200000})
//创建合约实例。括号内部的from后填写的是你账户的地址。gas后填写你愿意支付的gas。原则上大于刚刚估计的值。
  • 查看合约信息
1
2
3
4
5
6
7
8
9
10
contract1 
txpool.status
//这个命令可以看到有没有待挖矿的交易。我们可以看到有一个。
miner.start()
miner.stop()
//挖一会矿再停下来。
txpool.status
//待挖矿交易变为0。就说明合约已经写入链上了。
contract1.address
//调用这个可以看到我们部署到链上的合约的地址了。这个值保存下来。以后要用到。
  • 至此合约已经部署到了我们搭建的私链上了。

  • 如何调用已经部署好的合约
1
2
3
# 重新启动Geth控制台或者使用其他包时,调用原来部署好的智能合约要通过合约地址。
# 没有写入链上的变量在经历重启geth或者重启web3程序时都会没有了。但是如果部署好的智能合约,并且写入数据时运用的交易都挖矿写入链中了。那么再次通过地址调用时关于合约的数据就都还保留。
# 下面示例在Geth中调用合约的方法。假设我们现在已经重启了Geth控制台,首先还是要用合约地址实例化一个合约出来。
1
2
3
4
5
6
var abi=JSON.parse(‘合约的abi’)
//录入ABI。格式同上一节
myContract = eth.contract(abi)
//创建类
contract = myContract.at(address)
//创建合约实例,这里要指名部署过的合约地址。地址先前已经保存。

通过geth控制台调用智能合约中的函数
智能合约中的函数分为两类,一种是需要付gas才能调用的函数,一种是无需花费gas的函数。这两类函数在geth控制台中被调用时用到的命令不一样,这里分别举两个例子。

1
2
3
4
5
6
personal.unlockAccount(eth.coinbase)
//记得先解锁账户
contract.函数名.sendTransaction("参数1","参数2","参数...",{from:"0xe473d288faf6c2d1812dbb759d7423605c7d1a58"})
//上面是在geth控制台调用transactionn类型(要付gas类的)函数的方法。函数名要替换成自己的,括号内部前部分为函数的参数,分别列出,最后一项大括号内from要写付费的用户的地址(换成自己的)。
contract.函数名.call("参数1","参数2", "参数...")
//调用call类型函数的方法,(不要付gas类的)。

所有函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
> eth.
eth._requestManager eth.getBlockTransactionCount eth.getUncle
eth.accounts eth.getBlockUncleCount eth.getWork
eth.blockNumber eth.getCode eth.hashrate
eth.call eth.getCoinbase eth.iban
eth.chainId eth.getCompilers eth.icapNamereg
eth.coinbase eth.getGasPrice eth.isSyncing
eth.compile eth.getHashrate eth.mining
eth.constructor eth.getHeaderByHash eth.namereg
eth.contract eth.getHeaderByNumber eth.pendingTransactions
eth.defaultAccount eth.getMining eth.protocolVersion
eth.defaultBlock eth.getPendingTransactions eth.resend
eth.estimateGas eth.getProof eth.sendIBANTransaction
eth.fillTransaction eth.getProtocolVersion eth.sendRawTransaction
eth.filter eth.getRawTransaction eth.sendTransaction
eth.gasPrice eth.getRawTransactionFromBlock eth.sign
eth.getAccounts eth.getStorageAt eth.signTransaction
eth.getBalance eth.getSyncing eth.submitTransaction
eth.getBlock eth.getTransaction eth.submitWork
eth.getBlockByHash eth.getTransactionCount eth.syncing
eth.getBlockByNumber eth.getTransactionFromBlock
eth.getBlockNumber eth.getTransactionReceipt
> personal.
personal._requestManager personal.getListWallets personal.lockAccount personal.signTransaction
personal.constructor personal.importRawKey personal.newAccount personal.unlockAccount
personal.deriveAccount personal.initializeWallet personal.openWallet personal.unpair
personal.ecRecover personal.listAccounts personal.sendTransaction
personal.getListAccounts personal.listWallets personal.sign
> miner.
miner.constructor miner.propertyIsEnumerable miner.setRecommitInterval miner.toString
miner.getHashrate miner.setEtherbase miner.start miner.valueOf
miner.hasOwnProperty miner.setExtra miner.stop
miner.isPrototypeOf miner.setGasPrice miner.toLocaleString

Part3 本地环境信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
> admin
{
datadir: "D:\\gethData",
nodeInfo: {
enode: "enode://fac072814049255eb2f4c8c2c381183d87ee519d93600852cdcabd7dc3d9224d916be319bb2bfed89430112225f338d9dc15ea818f89cd242e46a05dd6bd63a7@192.168.136.117:30303",
enr: "enr:-Je4QFYrz1dcrKYsGSKlFZARRs4T6pki558pyHzIb1294oLWfgVCCLANovQUjqPjxi7jqfHjS_Elg3BI97K7JyFtbVACg2V0aMfGhMmaRmeAgmlkgnY0gmlwhMCoiHWJc2VjcDI1NmsxoQP6wHKBQEklXrL0yMLDgRg9h-5RnZNgCFLNyr19w9kiTYN0Y3CCdl-DdWRwgnZf",
id: "8a2d0a9309f63565292f84e6286532af5abc27df6abfb93f49c0d2d077b9666d",
ip: "192.168.136.117",
listenAddr: "[::]:30303",
name: "Geth/v1.9.23-stable-8c2f2715/windows-amd64/go1.15",
ports: {
discovery: 30303,
listener: 30303
},
protocols: {
eth: {
config: {...},
difficulty: 2000,
genesis: "0xdc9866ac4601761e6b960e690eb144c03dd48e7125c99e14ecf0a0af5d739224",
head: "0xdc9866ac4601761e6b960e690eb144c03dd48e7125c99e14ecf0a0af5d739224",
network: 16
}
}
},
peers: [{
caps: ["eth/63"],
enode: "enode://8192f9e5cfa8fb73e914c39e830211ab2b98d6180df1cf009c1b1c9ddad3bb6d09d986db5ee125f4bb59c226014e72975f170c734774cc389ccb6e6f73fcce34@174.138.19.97:1234",
id: "f227374bcd5f39fff43a333f04cbe43393f5db0baf5eb4ebddd9c8a9ae6fdfbe",
name: "Geth/v1.0.0-stable-7e368c8e/linux-amd64/go1.12.10",
network: {
inbound: false,
localAddress: "192.168.1.118:50638",
remoteAddress: "174.138.19.97:1234",
static: false,
trusted: false
},
protocols: {
eth: "handshake"
}
}, {
caps: ["eth/63", "eth/64", "eth/65"],
enode: "enode://5928e6c7a1b9c90014b5b5ef5fbd305636b477f2e35b5c608ed7fae82e0ea3295be2c716ec50de640e5b0665c44f652cde5c9f3a6e4bcf134657a6944cd91d39@149.5.29.162:30303",
id: "f24d4969e9e4f171b36d962f15ea1bc25b037731a99eee25887b02d1437d09ac",
name: "Pirl/v1.9.12-v7-masternode-premium-lion-ea07aebf-20200407/linux-amd64/go1.13.6",
network: {
inbound: false,
localAddress: "192.168.1.118:50661",
remoteAddress: "149.5.29.162:30303",
static: false,
trusted: false
},
protocols: {
eth: "handshake"
}
}],
addPeer: function(),
addTrustedPeer: function(),
clearHistory: function(),
exportChain: function(),
getDatadir: function(callback),
getNodeInfo: function(callback),
getPeers: function(callback),
importChain: function(),
removePeer: function(),
removeTrustedPeer: function(),
sleep: function(),
sleepBlocks: function(),
startRPC: function(),
startWS: function(),
stopRPC: function(),
stopWS: function()
}

personal
> personal
{
listAccounts: ["0xc59256c9f92d19e877d4a9931652ccbcd1260076"],
listWallets: [{
accounts: [{...}],
status: "Locked",
url: "keystore://D:\\gethData\\keystore\\UTC--2020-11-10T00-51-59.108912200Z--c59256c9f92d19e877d4a9931652ccbcd1260076"
}],
deriveAccount: function(),
ecRecover: function(),
getListAccounts: function(callback),
getListWallets: function(callback),
importRawKey: function(),
initializeWallet: function(),
lockAccount: function(),
newAccount: function(),
openWallet: function(),
sendTransaction: function(),
sign: function(),
signTransaction: function(),
unlockAccount: function(),
unpair: function()
}

miner
> miner
{
getHashrate: function(),
setEtherbase: function(),
setExtra: function(),
setGasPrice: function(),
setRecommitInterval: function(),
start: function(),
stop: function()
}

eth
> eth
{
accounts: ["0xc59256c9f92d19e877d4a9931652ccbcd1260076"],
blockNumber: 0,
coinbase: "0xc59256c9f92d19e877d4a9931652ccbcd1260076",
compile: {
lll: function(),
serpent: function(),
solidity: function()
},
defaultAccount: undefined,
defaultBlock: "latest",
gasPrice: 1000000000,
hashrate: 0,
mining: false,
pendingTransactions: [],
protocolVersion: "0x41",
syncing: false,
call: function(),
chainId: function(),
contract: function(abi),
estimateGas: function(),
fillTransaction: function(),
filter: function(options, callback, filterCreationErrorCallback),
getAccounts: function(callback),
getBalance: function(),
getBlock: function(),
getBlockByHash: function(),
getBlockByNumber: function(),
getBlockNumber: function(callback),
getBlockTransactionCount: function(),
getBlockUncleCount: function(),
getCode: function(),
getCoinbase: function(callback),
getCompilers: function(),
getGasPrice: function(callback),
getHashrate: function(callback),
getHeaderByHash: function(),
getHeaderByNumber: function(),
getMining: function(callback),
getPendingTransactions: function(callback),
getProof: function(),
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()
}
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信