以太坊多节点私有链部署

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了以太坊多节点私有链部署相关的知识,希望对你有一定的参考价值。

参考技术A 假设两台电脑A和B
要求:
1、两台电脑要在一个网络中,能ping通
2、两个节点使用相同的创世区块文件
3、禁用ipc;同时使用参数--nodiscover
4、networkid要相同,端口号可以不同

1.4 搭建私有链
1.4.1 创建目录和genesis.json文件
创建私有链根目录./testnet
创建数据存储目录./testnet/data0
创建创世区块配置文件./testnet/genesis.json

1.4.2 初始化操作
cd ./eth_test
geth --datadir data0 init genesis.json

1.4.3 启动私有节点

1.4.4 创建账号
personal.newAccount()
1.4.5 查看账号
eth.accounts
1.4.6 查看账号余额
eth.getBalance(eth.accounts[0])
1.4.7 启动&停止挖矿
启动挖矿:
miner.start(1)
其中 start 的参数表示挖矿使用的线程数。第一次启动挖矿会先生成挖矿所需的 DAG 文件,这个过程有点慢,等进度达到 100% 后,就会开始挖矿,此时屏幕会被挖矿信息刷屏。
停止挖矿,在 console 中输入:
miner.stop()
挖到一个区块会奖励5个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做 coinbase,默认情况下 coinbase 是本地账户中的第一个账户,可以通过 miner.setEtherbase() 将其他账户设置成 coinbase。

1.4.8 转账
目前,账户 0 已经挖到了 3 个块的奖励,账户 1 的余额还是0:

我们要从账户 0 向账户 1 转账,所以要先解锁账户 0,才能发起交易:

发送交易,账户 0 -> 账户 1:

需要输入密码 123456

此时如果没有挖矿,用 txpool.status 命令可以看到本地交易池中有一个待确认的交易,可以使用 eth.getBlock("pending", true).transactions 查看当前待确认交易。

使用 miner.start() 命令开始挖矿:
miner.start(1);admin.sleepBlocks(1);miner.stop();

新区块挖出后,挖矿结束,查看账户 1 的余额,已经收到了账户 0 的以太币:
web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')

用同样的genesis.json初始化操作
cd ./eth_test
geth --datadir data1 init genesis.json

启动私有节点一,修改 rpcport 和port

可以通过 admin.addPeer() 方法连接到其他节点,两个节点要要指定相同的 chainID。

假设有两个节点:节点一和节点二,chainID 都是 1024,通过下面的步骤就可以从节点二连接到节点一。

首先要知道节点一的 enode 信息,在节点一的 javascript console 中执行下面的命令查看 enode 信息:

admin.nodeInfo.enode
" enode://d465bcbd5c34da7f4b8e00cbf9dd18e7e2c38fbd6642b7435f340c7d5168947ff2b822146e1dc1b07e02f7c15d5ca09249a92f1d0caa34587c9b2743172259ee@[::]:30303 "

然后在节点二的 JavaScript console 中执行 admin.addPeer(),就可以连接到节点一:

addPeer() 的参数就是节点一的 enode 信息,注意要把 enode 中的 [::] 替换成节点一的 IP 地址。连接成功后,节点一就会开始同步节点二的区块,同步完成后,任意一个节点开始挖矿,另一个节点会自动同步区块,向任意一个节点发送交易,另一个节点也会收到该笔交易。

通过 admin.peers 可以查看连接到的其他节点信息,通过 net.peerCount 可以查看已连接到的节点数量。

除了上面的方法,也可以在启动节点的时候指定 --bootnodes 选项连接到其他节点。 bootnode 是一个轻量级的引导节点,方便联盟链的搭建 下一节讲 通过 bootnode 自动找到节点

参考: https://cloud.tencent.com/developer/article/1332424

以太坊私有链下智能合约部署

上一篇文章实现了搭建私有链,以下进行智能合约的部署

一、 编写合约

简单的乘法例子:

pragma solidity ^0.4.2;
contract test {

   function multiply(uint a) returns(uint d) {
       return a * 7;
   }
}

 

二、 编译合约

推荐网站:here

得到:Interface 和 Bytecode 和 Web3 deploy

Bytecode: 6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a723058206f9974e7f2c8329cbc09530d06d001018bfeca369c7cd8f9d565298adbdd2a9c0029

Interface: [{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

Web3 deploy:
var browser_ballot_sol_testContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]);
var browser_ballot_sol_test = browser_ballot_sol_testContract.new(
   {
     from: web3.eth.accounts[0], 
     data: ‘0x6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a723058206f9974e7f2c8329cbc09530d06d001018bfeca369c7cd8f9d565298adbdd2a9c0029‘, 
     gas: ‘4300000‘
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== ‘undefined‘) {
         console.log(‘Contract mined! address: ‘ + contract.address + ‘ transactionHash: ‘ + contract.transactionHash);
    }
 })

 

 

三、 部署合约

在部署合约前,我们要明确需要以下几项条件:

  1. 一个有Ether的账户;
  2. 该账户已解锁;
  3. 编译合约得到的abi和code。

所以首先需要做以下工作:

//创建账户
personal.newAccount(‘密码‘)

//挖矿,获得ether
miner.start()
miner.stop()

//账户解锁
personal.unlockAccount("第一个账户地址", "密码")

 

第一步: 获取abi信息,即上述编译得到的interface

abi = [{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

 

得到结果:

[{
    constant: false,
    inputs: [{
        name: "a",
        type: "uint256"
    }],
    name: "multiply",
    outputs: [{
        name: "d",
        type: "uint256"
    }],
    payable: false,
    stateMutability: "nonpayable",
    type: "function"
}]
> 

 

第二步:

multiplyContract = web3.eth.contract(abi)

得到结果:

{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "multiply",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  eth: {
    accounts: ["0xbe98c12f918275591c9a43ec3c7bc44cfca50d2f"],
    blockNumber: 7,
    coinbase: "0xbe98c12f918275591c9a43ec3c7bc44cfca50d2f",
    compile: {
      lll: function(),
      serpent: function(),
      solidity: function()
    },
    defaultAccount: undefined,
    defaultBlock: "latest",
    gasPrice: 18000000000,
    hashrate: 0,
    mining: false,
    pendingTransactions: [],
    protocolVersion: "0x3f",
    syncing: false,
    call: function(),
    ... (一堆function)
}

 

第三步: 复制 Web3 deploy 到命令行

multiply = multiplyContract.new(
   {
     from: web3.eth.accounts[0], 
     data: ‘0x6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a723058206f9974e7f2c8329cbc09530d06d001018bfeca369c7cd8f9d565298adbdd2a9c0029‘, 
     gas: ‘4300000‘  //改为300000
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== ‘undefined‘) {
         console.log(‘Contract mined! address: ‘ + contract.address + ‘ transactionHash: ‘ + contract.transactionHash);
    }
 })

 

得到结果

{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "multiply",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: undefined,
  transactionHash: "0x87400471a0e32edcfa9e1ca621d08a318e9abb85299d280deb8bc199e118427f"
}

 

==> 在这一步,可能你会得到一条错误信息:

invalid sender undefined

 

解决方法: 在genesis.json文件中,chainId 不能设置为0。 如果你完全按照github上给的官方配置文件,就会产生这个错误

==> 在这一步,可能你会得到一条错误信息:

Error: authentication needed: password or unlock undefined

 

解决方法:先解锁账户啦

personal.unlockAccount("第一个账户地址", "密码")

 

==> 在这一步,可能你还会遇到这个问题:

Error: exceeds block gas limit undefined
The contract code couldn‘t be stored, please check your gas amount. undefined

 

解决方法:把gas改为300000。直接从那个网站的Web3 deploy 复制可能是4300000,然后改成300000,就没问题了。

猜测原因:

eth.getBlock("pending").gasLimit
web3.eth.estimateGas({data: bytecode})

可以先输入这两条来预判一下范围,取中间值。

 

第四步:然后我们需要挖矿确认

miner.start()

等待一会,你会得到一条信息:
Contract mined! address: 0xdb385bc97ed9fbac62920102d5edc7c4bf993c79 transactionHash: 0x87400471a0e32edcfa9e1ca621d08a318e9abb85299d280deb8bc199e118427f
==> 就代表部署成功啦。

miner.stop()

 

四、合约交互

第一步:获取合约对象

MyContract = eth.contract(abi)

 

得到结果:

{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "multiply",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  eth: {
    accounts: ["0xd88ad6d115ed640b69f01e24ff1433f75d5c8f87"],
    blockNumber: 4,
    coinbase: "0xd88ad6d115ed640b69f01e24ff1433f75d5c8f87",
    compile: {
      lll: function(),
      serpent: function(),
      solidity: function()
    },
    defaultAccount: undefined,
    defaultBlock: "latest",
    gasPrice: 18000000000,
    hashrate: 612,
    mining: false,
    pendingTransactions: [],

    ...(一堆function)
}

第二步:实例化合约

myContract = MyContract.at(multiply.address)

 

得到结果:

{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "multiply",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: "0xdb385bc97ed9fbac62920102d5edc7c4bf993c79",
  transactionHash: null,
  allEvents: function(),
  multiply: function()
}

 

第三步:调用合约

myContract.multiply.call(5)

 

得到结果:

35

 

五、在电脑B调用该合约

确定两台电脑已成功连接。电脑B上新建账户,并解锁。

1. abi = [{constant:false,inputs:[{name:‘a‘,type:‘uint256‘}],name:‘multiply‘,outputs:[{name:‘d‘,type:‘uint256‘}],type:‘function‘}]  //合约的abi
2. address = 0xdb385bc97ed9fbac62920102d5edc7c4bf993c79  // 合约地址
3. myContract = web3.eth.contract(abi).at(address)

==> 然后就可以调用使用了 myContract.multiply.call(5)
得到结果:35

以上是关于以太坊多节点私有链部署的主要内容,如果未能解决你的问题,请参考以下文章

Polygon SDK以太坊多链开发包

以太坊(区块链)部署

体验篇 - 部署以太坊私有链 (PoA)

以太坊私有链下智能合约部署

如何搭建以太坊私有链

如何搭建以太坊私有链