Home > 感悟 > 基于以太坊私有链搭建一个分布式应用【2】

基于以太坊私有链搭建一个分布式应用【2】0+

5,890 views / 2018.03.15 / 10:10 下午

 

合约编写

 

合约编辑器有很多,我们用这个IDE http://remix.ethereum.org/

合约格式是sol,需要编译成js文件让geth执行。以上工具可以方便的实现。

Conference.sol示例:

pragma solidity ^0.4.19;

 

contract Conference {  // can be killed, so the owner gets sent the money in the end

 

address public organizer;

mapping (address => uint) public registrantsPaid;

uint public numRegistrants;

uint256 public ticketPrice;

uint public quota;

 

event Deposit(address _from, uint _amount); // so you can log the event,more information to see http://71j.cn

event Refund(address _to, uint _amount); // so you can log the event,more information to see http://71j.cn

 

function Conference() public{

organizer = msg.sender;

quota = 100;

ticketPrice = 1 ether;

numRegistrants = 0;

}

/** 1 msg 指谁调用该智能合约发来的信息。 注意:智能合约也是一个账户

* 2 msg 包含的成员:

* msg.data(bytes): 获取调用者传入的数据信息

* msg.gas(uint): 剩余的以太币

* msg.sender(address): 当前调用者的以太坊账户地址

* msg.sig(bytes4): first four bytes of cakkData

* msg.value(uint): number of wei sent with the message;注意: 只有当有以太坊币的转义时, 该变量才有值(除调用合约所花费以太币这种情况)

*/

function buyTicket(uint ticketNumber) payable public {

require(ticketNumber>0);

require(numRegistrants+ticketNumber <= quota);

uint totalPrice = ticketNumber*ticketPrice;

require(msg.value==totalPrice);

registrantsPaid[msg.sender] += totalPrice;

numRegistrants+=ticketNumber;

//this.transfer(totalPrice);

organizer.transfer(totalPrice);

Deposit(msg.sender, totalPrice);

}

/*Contracts that receive Ether directly (without a function call, i.e. using send or transfer) but do not define a fallback function throw an exception, sending back the Ether (this was different before Solidity v0.4.0). So if you want your contract to receive Ether, you have to implement a fallback function.

*/

function () public payable {

/*只要有支付行为,就会调用这个后备

函数。举例:

*合约计划仅接受用户转入指定价值的eth,如果用户转入eth较少,则直接返回异常,当用户转入eth较多,则将用户多转入的eth退回。

*在这里我们可以借助 fallback function,也就是后备函数进行转入金额的限定。

*/

 

}

 

function changeQuota(uint newquota) public {

require(msg.sender == organizer);

quota = newquota;

}

 

function refundTicket(address recipient, uint amount,uint ticketNumber) payable public{

require(msg.sender == organizer);

if (registrantsPaid[recipient] >= amount) {

//address myAddress = this;

if (organizer.balance >= amount) {

recipient.transfer(amount);

Refund(recipient, amount);

registrantsPaid[recipient] -= amount;

numRegistrants-=ticketNumber;

}

}

return;

}

 

 

function destroy () public{

require(msg.sender == organizer);// without this funds could be locked in the contract forever!

selfdestruct(organizer);

 

}

}

*在Node1命令行中审视一下自己编辑的合约:solc –gas Conference.sol

*网上说以太坊在标准库方面只实现了非常非常少的一部分,比如SHA3.SHA3操作的基本开销是30gas,之后每个32字节的数据hash需要3gas。内置的StringEqual操作需要5 gas的基本开销,随后比较每个字节需要1 gas

 

用IDE编译成Conference,js后,回到geth,可以导入合约。!注意,这个过程矿机不能停。!

 

> loadScript(‘./Conference.js’)

null [object Object]

true

> null [object Object]

Contract mined! address: 0xcbf1b22ad7eda3482f7f00948539ea5684a6882b transactionHash: 0xb7c3a8c1282baef3c7b7063b1a96b10e28ff26a2c1fe9fd5a3c81ccbafcbea7d

 

我们可以看到合约有一个address,意味着它能收发以太值,以及一个transactionHash,用它来找到区块链中的位置。直接输入ss(我们初始化的实例名字),发现合约的abi信息以及公共的可调用的函数也列出了。abi是Application Binary Interface的缩写,字面意思 应用二进制接口,可以通俗的理解为合约的接口说明。当合约被编译后,那么它的abi也就确定

现在让我们调用下:

ss.changeQuota.sendTransaction(100)

Error: invalid address

at web3.js:3930:15

at web3.js:3756:20

at web3.js:5025:28

at map (<native code>)

at web3.js:5024:12

at web3.js:5050:18

at web3.js:5075:23

at web3.js:4137:16

at <anonymous>:1:1

我去,没成功。再试试这个:

> ss.quota()

100

> ss.changeQuota.sendTransaction(200,{from:eth.coinbase})

“0x44acef0216b4da50e32a25bdaaf074ddd349f23280f181bf0d284c32769830d2”

> ss.quota()

100

> ss.quota()

200

由于web3.js封装了合约调用的方法。我们可以使用可以使用web3.eth.contract的里的sendTransaction来修改区块链数据。在这里有个坑,有可能会出现Error: invalid address,原因是没有传from,交易发起者的地址。在使用web3.js的API都需留意,出现这种找不到地址的,都看看from字段吧。

 

接下来看看gas消耗的情况:

Node1:

> ss.organizer()

“0xf4182f0dc92313f8e106fc033641c3351703911f”

> eth.getBalance(“0xf4182f0dc92313f8e106fc033641c3351703911f”)

2.0000037903157114008e+28

为了保证合约内容讲解的完成性,这块我们要穿越到第二天Node2节点已经搭建完成了!

Node2:

var bb=eth.contract.(abi).at(address);//这是在新节点初始化合约的方法

> personal.unlockAccount(eth.coinbase)

Unlock account 0xf2ad598bb92b28989d1e8bf686f0e07a8a036a5a

Passphrase:

true

> eth.getBalance(eth.coinbase)

9.574379388346e+21

> bb.buyTicket.sendTransaction(2,{from:eth.coinbase,value:web3.toWei(2)})

“0x2f5bf547eadbff0c96db240aa896990142bd23f769be87f2e459261caf8d633c”

> eth.getBalance(eth.coinbase)

9.572378091716e+21

> eth.getTransaction(“0x2f5bf547eadbff0c96db240aa896990142bd23f769be87f2e459261caf8d633c”)

{

blockHash: “0xb207210430239571b5d999c4c000f065d66e660b64045e6218e179a817f8c006”,

blockNumber: 8422,

from: “0xf2ad598bb92b28989d1e8bf686f0e07a8a036a5a”,

gas: 90000,

gasPrice: 18000000000,

hash: “0x2f5bf547eadbff0c96db240aa896990142bd23f769be87f2e459261caf8d633c”,

input: “0x67dd74ca0000000000000000000000000000000000000000000000000000000000000002”,

nonce: 42,

r: “0xef743cab7bdf70706052877ab675a289094a56e1f0241f618b7eb7ad73b273a7”,

s: “0x5cb18b44f1e3276c8f695ad126a578ebe1badd2f532b7d4139592eb2bd3e05f7”,

to: “0xfbcd7a73ff412512117300f59248f4281579c80f”,

transactionIndex: 0,

v: “0x3c”,

value: 2000000000000000000

}

>  9.574379388346e+21-9.572378091716e+21//少了这么多钱

2001296630000648200

> 2001296630000648200-2000000000000000000//减掉票钱

1296630000648192

> 1296630000648192/18000000000

72035.00003601066//大概花了这么多gas

 

创建新Node

登录246服务器,修改genesis.json!!!!!错误!!!!这文件一个字都不能改。

geth –datadir “/home/appadmin/.ethereum” init eth/genesis.json

./start.sh删除unlock和password, 修改rpcaddr为246

 

 

在Node1的 boot node 上获取 enode 信息

> admin.nodeInfo.enode

“enode://2794bb6a9439d80c55c394328b396105adff8f5a2c9686fd56945024ebadb847ac2bbca2266742138ddfb94a03ceccbcd98b1caffc4820d1ead5c369234aad8b@[::]:30303”

替换:

“enode://2794bb6a9439d80c55c394328b396105adff8f5a2c9686fd56945024ebadb847ac2bbca2266742138ddfb94a03ceccbcd98b1caffc4820d1ead5c369234aad8b@10.120.113.245:30303”

将 boot node 的 enode 信息写入 node2

>admin.addPeer(“enode://2794bb6a9439d80c55c394328b396105adff8f5a2c9686fd56945024ebadb847ac2bbca2266742138ddfb94a03ceccbcd98b1caffc4820d1ead5c369234aad8b@10.120.113.245:30303”)

true

> admin.peers

[]

> admin.peers

[{

caps: [“eth/62”, “eth/63”],

id: “edcc39c963e128555c192be58ddd387a674aba2123ec7daef9144b6ff109ac5712bcfea3904a63031fcdbbfae30c26bb6148af0c559944b34f00d0cd2889688c”,

name: “Geth/v1.8.2-stable-b8b9f7f4/linux-amd64/go1.9.4”,

network: {

inbound: true,

localAddress: “10.120.113.245:30303”,

remoteAddress: “10.120.113.246:48204”,

static: false,

trusted: false

},

protocols: {

eth: {
difficulty: 7035219,

head: “0xf8b772c1b23cd8bea305aa52f13cd68a1697339e86f9badd5d064502c3c84e65”,

version: 63

}

}

}]

也可以在start.sh中直接指定Node1的信息

#!/bin/sh

geth –ipcdisable –rpc –rpcaddr “10.120.113.246”  –port 30303 –rpcport 8101 –rpccorsdomain “*” –networkid 12 –datadir ‘~/.ethereum’ –bootnodes “enode://3d6ff07e12e59a4dbd972e5d8ed33578570203c852f9837b263a04fa91bc9c795b46cbd3ee801a67aa741e317fcd734409bf1e81c8a4e81e6e27f420fd25ba0a@10.120.113.245:30303” console 2>>log

这样新节点就添加完成了,他们之间的通信就是p2p的方式了。

本站内容受著作权法保护。个人 blog 转载时请遵循 “署名-非商业用途-保持一致” 的创作共用协议;商业网站或未授权媒体不得复制本站内容。
Categories: 感悟 Tags:

Comments (0) Trackbacks (0) 本篇共有 0 篇评论↓
  1. No comments yet.
  1. No trackbacks yet.