汪晓明对区块链、以太坊的思考

记录创业、生活的所思所感,探讨去中心化思想,推动区块链的发展。

以太坊连载(24):集成开发环境(IDE) Mix介绍

Mix

IDE Mix旨在作为开发者帮你创建,排错和部署合约及去中心化应用(后端和前端的合约)

警告 – 有很多OS X上关于Mix的crash-at-boot 事件报告。这个事件是Heisenbug,我们已经跟踪了一两个月。我们现有的最佳变通方案是用排错配置,像这样:

1
cmake -DCMAKE_BUILD_TYPE=Debug ..

警告 – 正在研究一个Mix的替代物,叫做Remix。如果你在Mix经历了事件,在Remix更成熟之前,你最好寻找替代方案。

从创建一个新项目开始,它包括

  • 合约
  • html 文件
  • JavaScript 文件
  • style 文件
  • image 文件

项目编辑器

你可以用项目来管理去中心化应用的创建和测试。项目会包括与后端和前端相关的数据以及和你的场景(区块链互动)相关的数据,用来排错和测试。相关文件 会被创建并自动保存到项目目录中。

创建一个新项目

去中心化应用的开发始于新项目的创建。在“编辑”菜单创建一个新项目。进入项目名称,比如 “等级”,选择项目文件路径。

编辑后端合约文件

一个新项目默认包含一个合约,“Contract”用于使用Solidity语言在区块链后端开发,“index.html”用于前端。查看Solidity教程或参考。 编辑空的默认合约“Contract”,比如

1
2
3
4
5
6
contract Rating {
  function setRating(bytes32 _key, uint256 _value) {
    ratings[_key] = _value;
    mapping (bytes32 => uint256) public ratings;
  }
}

查看Solidity教程寻求帮助,以solidity编程语言开始。

保存变动

编辑前端html文件 选择默认index.html文件并输入以下代码

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
 .... <script>
function getRating() {
  var param = document.getElementById(query).value;
  var res = contracts[Rating].contract.ratings(param);
  document.getElementById(queryres).innerText = res;
}
function setRating() {
        var key = document.getElementById("key").value;
        var value = parseInt(document.getElementById("value").value);
        var res = contracts["Rating"].contract.setRating(key, value);
}
</script>
    </head>
    <body bgcolor="#E6E6FA">
        <h1>Ratings</h1>
<div> Store:
            <input type="string" id="key">
            <input type="number" id="value">
            <button onclick="setRating()">Save</button>
</div> <div>
            Query:
            <input type="string" id="query" onkeyup='getRating()'>
            <div id="queryres"></div>
        </div>
    </body>
</html>

有可能添加很多合约文件和HTML, JavaScript, css文件

场景编辑器

场景可以用于检测合约和为合约排错。

一个场景就是一个本地区块链,区块可以在这里被挖矿而不需要工作量证明 –否则测试会很慢 ;)

一个场景包含一系列交易。通常,一个场景以去中心化应用的合约创建场景开始。 此外,进一步的交易会被添加测试并对去中心化应用排错。场景可以修正,例如,移除交易。注意如果要修正一个场景使之有效,需要进行重建。可以通过JS API用JS进行进一步测试。

万一打不开,可以点击F7或Windows > 展示右侧或主界面右上方的排错按钮来进入场景和排错器窗格。

创建和设置新场景

第一次启动Mix的时候,会创建一个空场景,比如,不包含任何交易。添加账户并命名为“MyAccount”,设置初始余额为1以太币。点击确认。将场景重命名为“Deploy”。

修正账户的初始以太币余额

实际上我们想做很多测试。编辑初始区块参数,将初始账户余额设置为1000 以太币。重建场景使它变得高效。

重建场景

每次交易被修正或账户被添加的时候,场景必须重建以修正使之高效。注意如果一个场景重建,网络前端(本地存储)可能也需要重置(Mix不会自动操作)。

创建交易

我们发送一些以太币给Bob。创建另一个名为“Bob”的账户,余额为0。在场景窗格创建一个新交易。点击“Add Tx…”,发送300以太币给Bob。添加一个区块。

改变和重新使用场景

创建一个新场景或从一个场景开始,和几个你先复制的交易

重命名场景

通过指定要被移除的交易来修正场景

重建场景

展示调用

一个合约调用就是一个功能调用。这不是交易, 因为合约调用不会改变状态。合约调用不是区块链的一部分,但是出于实用和用户体验设计的原因,在交易的同一功能层次展示调用很方便。JS图标提醒你这不是个交易而是个调用。要展示/隐藏调用,点击菜单里的场景 –> 展示调用。

状态查看器

这个面板区块在区块链面板下面,场景视图中。一旦区块链被运行,这个面板会展示区块链状态。

说到状态,我们意味着所有账户余额(包括合约和正常账户),存储(所有部署合约的全局变量)。这个面板的内容不是动态的,它取决于在区块链面板上选择的交易。这里展示的状态是执行所选择交易的状态结果。

在那种情况下,部署了2个合约,选择的(testCtr的部署)是最后一个。状态视图展示了TestCtr和BasicContract的存储。

交易浏览器

使用交易窗格

交易窗格使你能够探索交易接收,包括

  • 输入参数
  • 返回参数
  • 事件日志

要显示交易浏览器,点击每个交易右侧的倒三角图标,会扩展出交易详情:

然后你可以复制剪贴板上的交易内容,编辑当前交易(然后你要重新运行区块链), 或为交易排错。

JavaScript console

Mix将以下对象暴露在全局窗口的语境下

web3 – 以太坊JavaScript API

合约:合约对象集合。钥匙代表合约名称。值是包含以下属性的对象:

  • 合约: 合约对象实例 (像在web3.eth.contract里一样创建)
  • 地址: 上一个部署状态的合约地址(查看下面)
  • 界面: 合约ABI

查看JavaScript API 参考了解更多信息。

用JS控制台添加交易和本地调用

如果合约名字是“Sample”,功能名字是“set”,有可能进行一个交易来调用 “set”,方法是写:

1
contracts["Sample"].contract.set(14)

如果调用可以进行,可以通过写以下命令完成:

1
contracts["Sample"].contract.get.call()

也有可能用web3对象的所有属性和功能: https://github.com/以太坊/wiki/wiki/JavaScript-API

交易排错器

Mix支持Solidity和组件级别合约代码排错。你可以在两个模式中切换,检索你所需要的相关信息。

在任何执行阶段,以下信息都可用:

虚拟机堆栈 – 查看黄皮书获取虚拟机操作指南描述 调用堆栈 – 合约调用到另一个合约时会生长。双击堆栈框架来查看机器在框架里的状态。 存储 – 与合约相关的存储数据 内存 – 分配到这个执行点的机器内存 调用数据– 交易或调用参数

进入排错模式

交易详情扩展后,你可以转换到排错视图,点击“交易排错”按钮。

在排错模式和单步调试交易之间切换

这里打开了Solidity排错模式。用菜单按钮(排错 –> 显示虚拟机代码)在Solidity和以太坊虚拟机排错模式之前转换

  • 在solidity排错模式下单步调试交易
  • 在以太坊虚拟机排错模式下单步调试交易

Dapps部署

这个功能能够让用户在主区块链将当前的项目作为去中心化应用部署。

这会部署合约和登记前端资源。

部署过程包括3步:

  • 部署合约: 这一步会在主区块链部署合约。
  • 打包Dapp: 这一步用于打包和上传前端资源。
  • 注册: 要变成去中心化应用,以太坊浏览器(Mist或AlethZero)需要进入这个包裹。这一步会在资源存储的地方注册URL。

要部署去中心化应用,请遵守以下指令:

点击Deploy, Deploy to Network

这个模式对话框会显示三部分(参见以上):

  • 部署合约
  • 选择场景

“以太坊节点URL”是节点运行的位置,为了发起部署,一定会有一个节点在运行。

“选择部署场景”是强制步骤。Mix会执行选定场景里的交易(除与合约创建或合约调用不相关的所有交易)。Mix会在下面的面板上展示所有的交易和所有相关参数。

“使用的Gas”:取决于所选定的场景,Mix会展示使用的gas总量。

  • 部署场景

“部署账户”允许选择Mix会用于执行交易的账户。

“Gas价格”显示网络默认的gas价格。你也可以指定一个不同的值。

“部署成本”:取决于你想使用的以及选定场景的gas价格的值。这会显示部署所需的以太币数量。

“部署的合约”:没发生部署之前,这部分是空的。部署一完成,这部分就会被所有创建的合约地址填满。

“验证”:这会显示验证数量(在最后一个区块顶部生成的区块数量,最后一个区块包含最近的部署交易)。Mix跟踪所有的交易。如果有一个丢失(无效),它会展示在面板上。

  • 打包去中心化应用

“生成包裹”这一行为会创建一个新的文件夹并命名为“www”,这个文件夹会包含所有被映射到当前部署合约上的资源和脚本。为了发布去中心化应用,你需要把www文件夹托管在一个网络服务器(很快会被IPFS和SWARM代替)。库中默认是不存在web3.js的。如果你想要在网络浏览器使用去中心化应用,就需要把这个库加进来。

代码编辑器

这个编辑器提供代码编辑器的基本功能。

  • 在Solidity或JavaScript模式下,可以用自动补全插件(Ctrl + Space).
  • 增大/减小字体 (Ctrl +, Ctrl –)
  • 在Solidity模式下,可以显示gas预估值(工具-> 显示Gas预估值)。这会把所有需要最小量gas的所有状态都加亮显示。如果需要的gas变得很重要,颜色会变红。它也会显示最大的交易执行费用(每个功能)。

下一篇文章我们将会介绍《以太坊连载(25):Dapp及相关开发工具介绍》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(23):如何部署、调用智能合约

RPC

之前的章节中我们看到了怎么写、部署合约以及与合约互动。现在该讲讲与以太坊网络和智能合约沟通的细节了。

一个以太坊节点提供一个RPC界面。这个界面给Ðapp访问以太坊区块链的权限和节点提供的功能,比如编译智能合约代码,它用JSON-RPC 2.0规范(不支持提醒和命名的参数) 的子集作为序列化协议,在HTTP和IPC (linux/OSX上的unix域接口,在Windows上叫pipe’s)上可用。

如果你对细节不感兴趣,正在寻找使用javascript库的简便方法,你可以略过下面的章节,从Using Web3继续。

惯例

RPC界面使用一些惯例,它们不是JSON-RPC 2.0规范的一部分:

  • 数字是十六进制编码。做这个决定是因为有些语言对运行极大的数字没有或有很少的限制。为了防止这些错误数字类型是十六进制编码,由开发者来分析这些数字并正确处理它们。在维基页百科查看十六进制编码章节查看案例。
  • 默认区块数字,几个RPC 方法接受区块数字。在一些情况下,给出区块数字是不可能的或者不太方便。 在那样的情况下,默认区块数字可以是以下字符串中的一个[”earliest”, “latest”, “pending”]。在维基页面查看使用默认区块参数的RPC方法列表。

部署合约

我们会通过不同的步骤来部署下面的合约,只用到RPC界面。

1
2
3
4
5
6
7
contract Multiply7 {
   event Print(uint);
   function multiply(uint input) returns (uint) {
      Print(input * 7);
      return input * 7;
   }
}

要做的第一件事是确保HTTP RPC界面可用。这意味着我们在开始为geth供应—rpc标志,为eth提供-j标志。在这个例子中我们用私有开发链上的geth节点。通过这种方法,我们就不需要真实网络上的以太币了。

1
> geth --rpc --dev --mine --minerthreads 1 --unlock 0 console 2>>geth.log

这会在http://localhost:8545 上启动HTTP RPC界面。

注意:geth支持CORS查看—rpccorsdomain标志了解更多。

我们可以通过用curl检索coinbase地址和余额来证明界面正在运行。请注意这些例子中的数据在你本地的节点上会有所不同。如果你想要试试这些参数,视情况替换需要的参数。

1
2
3
4
> curl --data '{"jsonrpc":"2.0","method":"eth_coinbase", "id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"]}
> curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"], "id":2}' localhost:8545
{"id":2,"jsonrpc":"2.0","result":"0x1639e49bba16280000"}

记不记得我们说过数字是十六进制编码?在这个情况下,余额作为十六进制字符串以Wei的形式返还。如果我们希望余额作为数字以太币为单位,我们可以从控制台用web3。

1
2
> web3.fromWei("0x1639e49bba16280000", "ether")
"410"

现在我们在私有开发链上有一些以太币,我们就可以部署合约了。第一步是验证solidity编译器可用。我们可以用eth_getCompilers RPC method方法来检索可用的编译器。

1
2
> curl --data '{"jsonrpc":"2.0","method": "eth_getCompilers", "id": 3}' localhost:8545
{"id":3,"jsonrpc":"2.0","result":["Solidity"]}

我们可以看到solidity编译器可用。如果不可用,按照这些说明操作。

下一步是把Multiply7合约编译到可以发送给以太坊虚拟机的字节代码。

1
2
> curl --data '{"jsonrpc":"2.0","method": "eth_compileSolidity", "params": ["contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
{"id":4,"jsonrpc":"2.0","result":{"Multiply7":{"code":"0x6060604052605f8060106000396000f360606040

现在我们有了编译代码,需要决定花多少gas去部署它。RPC界面有eth_estimateGas方法,会给我们一个预估数量。

1
2
> curl --data '{"jsonrpc":"2.0","method": "eth_estimateGas", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 5}' localhost:8545
{"id":5,"jsonrpc":"2.0","result":"0xb8a9"}

最后部署合约。

1
2
> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "gas": "0xb8a9", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 6}' localhost:8545
{"id":6,"jsonrpc":"2.0","result":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08

交易由节点接受,交易散表被返还。我们可以用这个散表来跟踪交易。

下一步是决定部署合约的地址。每个执行的交易都会创建一个接收。这个接收包含交易的各种信息,比如交易被包含在哪个区块,以太坊虚拟机用掉多少gas。如果交易创建了一个合约,它也会包含合约地址。我们可以用eth_getTransactionReceipt RPC方法检索接收。

1
2
> curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08a7c"], "id": 7}' localhost:8545
{"id":7,"jsonrpc":"2.0","result":{"transactionHash":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c682

我们可以看到合约在0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d上被创建。如果你得到了零而不是接收,说明还没有被纳入区块。等一下,检查看看你的矿工是否在运行,重新试一遍。

和智能合约互动

现在已经部署了合约,我们可以和它互动了。有两种方法,发送交易或像之前所介绍的那样使用调用。在这个例子中,我们会发送交易到合约的multiply方法。

如果我们看eth_sendTransaction 的档案,可以发现我们需要提供几个参数。

在我们的实例中,需要具体说明from, to 和data参数。From是我们账户的公共地址,to是合约地址。Data参数有一点困难。它包括了规定调用哪个方法和哪个参数的负载量。这就需要ABI发挥作用了。ABI规定了如何为以太坊虚拟机规定和编码数据。你可以在这儿阅读ABI的所有具体信息。

负载量的字节是功能选择符,规定了调用哪个方法。它取Keccak散表的头4个字节,涵盖功能名称参数类型,并进行十六进制编码。multiply功能接受一个单元,也就是uint256的别名。这就让我们进行:

1
2
> web3.sha3("multiply(uint256)").substring(0, 8)
"c6888fa1"

在此页查看细节。

下一步是编码参数。我们只有一个unit256,让我们假定提供了值6。ABI有一个章节规定了怎么编码uint字节。

int: enc(X) is the big-endian two’s complement encoding of X, padded on the higher-oder (left) side with 0xff for negative X and with zero 字节s for positive X such that the length is a multiple of 32 bytes.

它编码到0000000000000000000000000000000000000000000000000000000000000006. 将功能选择符和编码参数结合起来,数据就会变成0xc6888fa10000000000000000000000000000000000000000000000000000000000000006.

我们来试一下:

1
2
> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "to": "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d", "data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}], "id": 8}' localhost:8545
{"id":8,"jsonrpc":"2.0","result":"0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869

由于我们发送了交易,于是有交易散表返回。如果我们检索接收,可以看到一些新内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55", blockNumber: 268,
contractAddress: null,
cumulativeGasUsed: 22631,
gasUsed: 22631,
logs: [{
      address: "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d",
      blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55",
      blockNumber: 268,
      data: "0x000000000000000000000000000000000000000000000000000000000000002a",
      logIndex: 0,
      topics: ["0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"],
      transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
      transactionIndex: 0
  }],
  transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
  transactionIndex: 0
}

接收包含一个日志。日志由以太坊虚拟机在交易执行时生成,包含接收。如果我们看Multiply功能,可以看到打印事件和输入次数7一起被提出。由于打印事件的参数是uint256,我们可以根据ABI规则对它进行编码,这样我们就会得到预期的十进制42.。除数据外,主题用于决定什么事件来创建日志,是毫无意义的:

1
2
> web3.sha3("Print(uint256)")
"24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"

你可以在Solidity教程中阅读更多关于事件,主题和索引的内容。

这只是对一些最常见任务的简单介绍。在RPC维基页面查看可用RPC方法的完整列表。

Web3.js

正如我们在之前的案例所见,使用JSON-RPC界面相当单调乏味且容易出错,尤其是在处理ABI的时候。Web3.js是javascript库,在以太坊RPC界面顶端。它的目标是提供更友好的界面,减少出错机会。

用web3部署Multiply7合约看起来是这样:

1
2
3
4
5
6
7
8
9
10
var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint
var compiled = web3.eth.compile.solidity(source);
var code = compiled.Multiply7.code;
var abi = compiled.Multiply7.info.abiDefinition;
web3.eth.contract(abi).new({from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", data: code}, func
   if (!err && contract.address)
      console.log("deployed on:", contract.address);
   }
);
deployed on: 0x0ab60714033847ad7f0677cc7514db48313976e2

装载一个部署的合约,发送交易:

1
2
3
4
5
var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
var compiled = web3.eth.compile.solidity(source);
var Multiply7 = web3.eth.contract(compiled.Multiply7.info.abiDefinition);
var multi = Multiply7.at("0x0ab60714033847ad7f0677cc7514db48313976e2")
multi.multiply.sendTransaction(6, {from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"})

注册一个回调,打印事件创建日志的时候会被调用。

1
2
multi.Print(function(err, data) { console.log(JSON.stringify(data)) })
{"address":"0x0ab60714033847ad7f0677cc7514db48313976e2","args": {"":"21"},"blockHash":"0x259c7dc0

在web3.js维基页面查看更多信息。

控制台

geth控制台提供命令行界面和javascript执行时间。它可以连接到本地或远程的geth或eth节点。它会装载用户能使用的web3.js库。这会允许用户从控制台用web3.js部署智能合约并和智能合约互动。实际上Web3.js章节的例子可以被复制进控制台。

查看合约与交易

有几个可用的在线区块链浏览器,能让你查询以太坊区块链。

查看列表:区块链浏览器。

在线区块链浏览器

  • EtherChain
  • EtherCamp
  • EtherScan (为测试网)

其他资源

  • EtherNodes – 节点的地理分配,由客户端区分
  • EtherListen – 实时以太坊交易可视器和可听器

下一篇文章我们将会介绍《以太坊连载(24):集成开发环境(IDE) Mix介绍》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(22):深入浅出智能合约

什么是合约?

合约是代码(它的功能)和数据(它的状态)的集合,存在于以太坊区块链的特定地址。 合约账户能够在彼此之间传递信息,进行图灵完备的运算。合约依靠被称作以太坊虚拟机(EVM) 字节代码(以太坊特有的二进制格式)上的区块链运行。

合约很典型地用诸如Solidity等高级语言写成,然后编译成字节代码上传到区块链上。

另请参阅:

也存在其他语言, 尤其是Serpent和LLL,在此文本的以太坊高级语言章节会进一步阐述。去中心化应用开发资源列出了综合的开发环境,帮助你用这些语言开发的开发者工具,提供测试,和部署支持等功能。

以太坊高级语言

合约依靠被称作以太坊虚拟机(EVM) 字节代码(以太坊特有的二进制格式)上的区块链运行。然而,合约很典型地用诸如Solidity等高级语言写成,然后用以太坊虚拟机编译器编译成字节代码上传到区块链。

下面是开发者可以用来为以太坊写智能合约的高级语言。

Solidity

Solidity是和JavaScript相似的语言,你可以用它来开发合约并编译成以太坊虚拟机字节代码。

它目前是以太坊最受欢迎的语言。

  • Solidity文本 – Solidity是以太坊的旗舰高级语言,用于写合约。
  • Solidity在线实时编译器
  • 标准合约API
  • 有用的去中心化模式 – 用于去中心化应用开发的代码片段。

Serpent

Serpent是和Python类似的语言,可以用于开发合约编译成以太坊虚拟机字节代码。它力求简洁, 将低级语言在效率方面的优点和编程风格的操作简易相结合,同时合约编程增加了独特的领域特定功能。Serpent用LLL编译。

  • 以太坊维基百科上的Serpent
  • Serpent以太坊虚拟机编译器

LLL

Lisp Like Language (LLL)是和Assembly类似的低级语言。它追求极简;本质上只是直接对以太坊虚拟机的一点包装。

  • GitHub上的LIBLLL
  • LLL实例

Mutan (弃用)

Mutan是个静态类型,由Jeffrey Wilcke 开发设计的C类语言。它已经不再受到维护。

写合约

没有Hello World程序,语言就不完整。Solidity在以太坊环境内操作,没有明显的“输出”字符串的方式。我们能做的最接近的事就是用日志记录事件来把字符串放进区块链:

1
2
3
4
contract HelloWorld {
  event Print(string out);
  function() { Print("Hello, World!"); } 
}

每次执行时,这个合约都会在区块链创建一个日志入口,印着“Hello,World!”参数。

另请参阅:

Solidity docs里有更多写Solidity代码的示例和指导。

编译合约

solidity合约的编译可以通过很多机制完成。

  • 通过命令行使用solc编译器。
  • 在geth或eth提供的javascript控制台使用web3.eth.compile.solidity (这仍然需要安装solc 编译器)。
  • 在线Solidity实时编译器。
  • 建立solidity合约的Meteor dapp Cosmo。
  • Mix IDE。
  • 以太坊钱包。

注意:关于solc和编译Solidity合约代码的更多信息可在此查看。

在geth设置solidity编译器

如果你启动了geth节点,就可以查看哪个编译器可用。

1
2
> web3.eth.getCompilers();
["lll", "solidity", "serpent"]

这一指令会返回到显示当前哪个编译器可用的字符串。

注意:solc编译器和cpp- ethereum一起安装。或者,你可以自己创建。

如果你的solc可执行文件不在标准位置,可以用—solc标志为solc可执行文件指定一个定制路线。

1
$ geth --solc /usr/local/bin/solc

或者你可以通过控制台在执行期间设置这个选项:

1
2
3
4
> admin.setSolc("/usr/local/bin/solc")
solc, the solidity compiler commandline interface
Version: 0.2.2-02bb315d/.-Darwin/appleclang/JIT linked to libethereum-1.2.0-8007cef0/.-Darwin/appleclang/JIT
path: /usr/local/bin/solc

编译一个简单合约

让我们编译一个简单的合约源:

1
> source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"

这个合约提供了一个单一方法multiply,它和一个正整数a调用并返回到a * 7 。

你准备在geth JS控制台用eth.compile.solidity()编译solidity代码:

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
> contract = eth.compile.solidity(source).test
{
  code: '605280600c6000396000f3006000357c01000000000000000000000000000000000000000000000000000000
  info: {
    language: 'Solidity',
    languageVersion: '0',
    compilerVersion: '0.9.13',
    abiDefinition: [{
      constant: false,
      inputs: [{
name: 'a',
        type: 'uint256'
      } ],
      name: 'multiply',
      outputs: [{
name: 'd',
        type: 'uint256'
      } ],
      type: 'function'
    } ],
    userDoc: {
      methods: {
      }
    },
    developerDoc: {
methods: {
} },
    source: 'contract test { function multiply(uint a) returns(uint d) { return a * 7; } }'
  }
}

注意:编译器通过RPC因此也能通过web3.js,对浏览器内任何通过RPC/IPC连接到geth的Ðapp可用。

下面的例子会向你展示如何通过JSON-RPC接合geth来使用编译器。

1
2
$ geth --datadir ~/eth/ --loglevel 6 --logtostderr=true --rpc --rpcport 8100 --rpccorsdomain ' * ' --mine console 2>> ~/eth/eth.log
$ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["contract test {

单源编译器输出会给出你合约对象,每个都代表一个单独的合约。eth.compile.solidity 的实际返还值是合约名字到合约对象的映射。由于合约名字是test,eth.compile.solidity(source).test会给出包含下列领域的测试合约对:

  • Code 编译的以太坊虚拟机字节代码
  • Info 从编译器输出的额外元数据
  • Source 源代码
  • Language 合约语言 (Solidity,Serpent,LLL)
  • LanguageVersion 合约语言版本
  • compilerVersion 用于编译这个合约的solidity编译器版本。
  • abiDefinition 应用的二进制界面定义
  • userDoc 用户的NatSpec Doc。
  • developerDoc 开发者的NatSpec Doc。

编译器输出的直接结构化(到code和info)反映了两种非常不同的部署路径。编译的以太坊虚拟机代码和一个合约创建交易被发送到区块,剩下的(info)在理想状态下会存活在去中心化云上,公开验证的元数据则执行区块链上的代码。

如果你的源包含多个合约,输出会包括每个合约一个入口,对应的合约信息对象可以用作为属性名称的合约名字检索到。你可以通过检测当前的GlobalRegistrar代码来试一下:

1
contracts = eth.compile.solidity(globalRegistrarSrc)

创建和部署合约

开始这一章节之前,确保你有解锁的账户和一些资金。 你现在会在区块链上创建一个合约,方法是用上一章节的以太坊虚拟机代码作为数据给空地址发送交易。

注意:用在线Solidity实时编译器或Mix IDE程序会更容易完成。

1
2
3
4
var primaryAddress = eth.accounts[0]
var abi = [{ constant: false, inputs: [{ name: 'a', type: 'uint256' } ]
var MyContract = eth.contract(abi)
var contract = MyContract.new(arg1, arg2, ..., {from: primaryAddress, data: evmByteCodeFromPrevio

所有的二进制数据都以十六进制的格式序列化。十六进制字符串总会有一个十六进制前缀0x。

注意:注意arg1, arg2, …是合约构造函数参数,以备它要接受参数。如果合约不需要构造函数参数,就可以忽略这些参数。

值得指出的是,这一步骤需要你支付执行。一旦交易成功进入到区块,你的账户余额(你作为发送方放在from领域)会根据以太坊虚拟机的gas规则被扣减。一段时间以后,你的交易会在一个区块中出现,确认它带来的状态是共识。你的合约现在存在于区块链上。 以不同步的方式做同样的事看起来是这样:

1
2
3
MyContract.new([arg1, arg2, ...,]{from: primaryAccount, data: evmCode}, function(err, contract) { if (!err && contract.address)
    console.log(contract.address);
});

与合约交互

与合约交互典型的做法是用诸如eth.contract()功能的抽象层,它会返回到javascript对象,和所有可用的合约功能一起,作为可调用的javascript功能。 描述合约可用功能的标准方式是ABI定义。这个对象是一个字符串,它描述了调用签名和每个可用合约功能的返回值。

1
2
var Multiply7 = eth.contract(contract.info.abiDefinition);
var myMultiply7 = Multiply7.at(address);

现在ABI中具体说明的所有功能调用都在合约实例中可用。你可以用两种方法中的一种来调用这些合约实例上的方法。

1
2
3
4
> myMultiply7.multiply.sendTransaction(3, {from: address})
"0x12345"
> myMultiply7.multiply.call(3)
21

当用sendTransaction被调用的时候,功能调用通过发送交易来执行。需要花费以太币来发送,调用会永久记录在区块链上。用这种方式进行的调用返回值是交易散表。

当用call被调用的时候,功能在以太坊虚拟机被本地执行,功能返回值和功能一起返回。用这种方式进行的调用不会记录在区块链上,因此也不会改变合约内部状态。这种调用方式被称为恒定功能调用。以这种方式进行的调用不花费以太币。

如果你只对返回值感兴趣,那么你应该用call 。如果你只关心合约状态的副作用,就应该用sendTransaction。

在上面的例子中,不会产生副作用,因此sendTransaction只会烧gas,增加宇宙的熵。

合约元数据

在之前的章节,我们揭示了怎样在区块链上创建合约。现在我们来处理剩下的编译器输出,合约元数据或者说合约信息。 当与不是你创建的合约交互时,你可能会想要文档或者查看源代码。合约作者被鼓励提供这样的可见信息,他们可以在区块链上登记或者借助第三方服务,比如说EtherChain。管理员API为所有选择登记的合约提供便利的方法来获取这个捆绑。

1
2
3
4
// get the contract info for contract address to do manual verification
var info = admin.getContractInfo(address) // lookup, fetch, decode
var source = info.source;
var abiDef = info.abiDefinition

这项工作的潜在机制是:

  • 合约信息被可以公开访问的URI上传到可辨认的地方
  • 任何人都可以只知道合约地址就找到是什么URI

仅通过2个步骤的区块链注册就可以实现这些要求。第一步是在被称作HashReg的合约中用内容散表注册合约代码(散表)。第二步是在UrlHint合约用内容散表注册一个url。这些注册合约是Frontier版本的一部分,已经参与到Homestead中。

要知道合约地址来查询url,获取实际合约元数据信息包,使用这一机制就足够了。

如果你是个尽职的合约创建者,请遵循以下步骤:

  1. 将合约本身部署到区块链
  2. 获取合约信息json文件
  3. 将合约信息json文件部署到你选择的任意url
  4. 注册代码散表 –>内容散表 –> url

JS API通过提供助手把这个过程变得非常容易。 调用admin.register从合约中提取信息,在指定文件中写出json序列,运算文件的内容散表,最终将这个内容散表注册到合约代码散表。一旦将那个文件部署到任意url,你就能用admin.registerUrl来注册url 和你区块链上的内容散表(注意一旦固定的内容选址模式被用作文件商店,url-hint不再必要了。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }" 
// compile with solc
contract = eth.compile.solidity(source).test
// create contract object
var MyContract = eth.contract(contract.info.abiDefinition)
// extracts info from contract, save the json serialisation in the given file, 
contenthash = admin.saveInfo(contract.info, "~/dapps/shared/contracts/test/info.json")

// send off the contract to the blockchain
MyContract.new({from: primaryAccount, data: contract.code}, function(error, contract){ 
  if(!error && contract.address) {
    // calculates the content hash and registers it with the code hash in `HashReg` 
    // it uses address to send the transaction.
    // returns the content hash that we use to register a url 
    admin.register(primaryAccount, contract.address, contenthash)
    // here you deploy ~/dapps/shared/contracts/test/info.json to a url
    admin.registerUrl(primaryAccount, hash, url)
  }
});

测试合约和交易

你通常需要低级的测试策略,为交易和合约排除故障。这一章节介绍了一些你可以用到的排错工作和做法。为了测试合约和交易而不产生实际的后果,你最好在私有区块链上测试。这可以通过配置一个替代网络ID (选择一个特别的数字)和/或不能用的端点来实现。推荐做法是,为了测试你用一个替代数据目录和端口 ,这样就不会意外地和实时运行的节点冲突(假定用默认运行。在虚拟机排错模式开启geth,推荐性能分析和最高的日志冗余级别 :

1
geth --datadir ~/dapps/testing/00/ --port 30310 --rpcport 8110 --networkid 4567890 --nodiscover -

提交交易之前,你需要创建私有测试链。参阅测试网络。

1
2
3
4
5
6
// create account. will prompt for password
personal.newAccount();
// name your primary account, will often use it
primary = eth.accounts[0];
// check your balance (denominated in ether)
balance = web3.fromWei(eth.getBalance(primary), "ether");
1
2
3
4
5
6
7
8
9
10
// assume an existing unlocked primary account
primary = eth.accounts[0];
// mine 10 blocks to generate ether
// starting miner
miner.start(4);
// sleep for 10 blocks (this can take quite some time).
admin.sleepBlocks(10);
// then stop mining (just not to burn heat in vain)
miner.stop();
balance = web3.fromWei(eth.getBalance(primary), "ether");

创建交易之后,你可以用下面的命令来强制运行:

1
2
3
miner.start(1);
admin.sleepBlocks(1);
miner.stop();

你可以用以下命令查看即将发生的交易:

1
2
3
4
5
6
// shows transaction pool
txpool.status
// number of pending txs
eth.getBlockTransactionCount("pending");
// print all pending txs
eth.getBlock("pending", true).transactions

如果你提交合约创建交易,可以检查想要的代码是否实际上嵌入到当前的区块链:

1
2
3
4
txhash = eth.sendTansaction({from:primary, data: code})
//... mining
contractaddress = eth.getTransactionReceipt(txhash);
eth.getCode(contractaddress)

下一篇文章我们将会介绍《以太坊连载(23):如何部署、调用智能合约》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(21):账户、交易核心概念及投注合约解析

外部账户 vs 合约账户

以太坊中有两种类型的账户

  • 外部账户
  • 合约账户

它们的区别在Serenity版本中可能会消失。

外部账户(EOA)

外部账户

  • 有以太币余额,
  • 可以发送交易(以太币交易或引发合约代码),
  • 由私钥控制,
  • 没有相关代码。

合约账户

合约

  • 有以太币余额,
  • 有相关代码,
  • 代码执行由从其他合约接收的交易或消息(调用)触发,
  • 执行的时候—执行任意复杂的操作(图灵完备的)—操控它自己的永久存储,例如,可以有自己的持久状态—可以调用其他合约

以太坊区块链上的所有行为都由外部账户引发的交易调动。每次合约账户接收到交易时,它的代码都按照输入参数的指示执行,作为交易的一部分发送。合约代码由参与到网络的每个节点上的以太坊虚拟机执行,作为验证新区块的一部分。

这个执行需要是完全确定性的,它唯一的语境是区块链上区块的位置和所有可见的数据。区块链上的区块代表时间单位,区块链本身是时间维度,代表在链上区块指定的离散的时间点上状态的整个历史。

所有的以太币余额和价值都以wei为单位命名:1个以太币是1e18 wei。

注意:以太坊中的“合约”不应该被看做是要“实现”或“遵守”的事物;它更像是在以太坊执行环境中生存的“自治代理”,被消息或交易“戳到”的时候,总会执行特定的代码片段,并且对自己的以太币余额和钥匙/价值商店有直接的控制,以储存永久状态。

什么是交易?

“交易”这个术语用在以太坊中来指代签署的数据包,数据包存储着要从外部账户发送到区块链上另一账户的消息。

交易包括:

  • 消息接收人,
  • 一个签字,用以确认发送方身份,证明通过区块链向接收者发送消息的意图,
  • VALUE域—从发送方向接收方转移的wei的数量,
  • 可选数据域,包括发送到合约的消息,
  • 一个STARTGAS值,代表交易执行允许采取的运算步骤的最大数量,
  • 一个GASPRICE值,代表发送人愿意支付的gas费用。一个gas单位对应着一个原子指令执行,比如运算步骤。

什么是消息?

合约能够向其他合约发送“消息”。消息是虚拟的事物,永远不能序列化,只存在于以太坊执行环境中。他们可以被想象为功能调用。

消息包括:

  • 消息发送方(内含的)
  • 消息接收方
  • VALUE域—和发送到合约地址的消息一起转移的wei数量,
  • 可选数据域,即发送到合约的实际数据
  • 一个STARTGAS值,限制了消息可以触发的代码执行的gas最大值。

本质上来说,一个消息就像一个交易,只不过消息是由合约而不是由外在因素创造的。当正在执行代码的合约执行CALL或DELEGATECALL 操作码时,消息就产生了。和交易一样,消息可能会导致接收方账户运行代码。因此,就像和外在因素建立关系一样,合约也能以同样的方式和其他合约建立关系。

什么是gas?

以太坊虚拟机(EVM)是以太坊区块链上的可执行环境。 每个参与到网络的节点运行EVM,作为区块验证协议的一部分。他们检查列在区块上的、他们验证的交易,运行EVM内部交易触发的代码。每个网络上的完整节点进行同样的运算,储存相同的值。很明显以太坊并不是关于运算效率的优化。它类似的进程是多余的。它的目的是提供一个有效的方式,在系统状态上不需要信任的第三方、准则或暴力垄断就能达成共识。但重要的是他们不是为了优化运算而存在。事实上,合约执行在节点之间被多余地重复,自然使之更昂贵,通常会鼓励人们如果能在链外操作运算,就不在区块链里进行。

运行去中心化应用(dapp)时,它和区块链互动来阅读和修正状态,但是去中心化应用会很典型地只把业务逻辑和对共识至关重要的状态放在区块链上。

当消息或交易触发结果执行时,每个指令在每个网络节点被执行。这有一个代价:每个执行的操作都有特定的成本,以一定量的gas单元表现。

Gas是交易发送方需要为每个以太坊区块链上发生的操作所支付的执行花费。这个名字gas的灵感来自这样一个观点,这笔花费就像加密燃料,驱使智能合约产生。Gas从执行代码的矿工处购买以获得以太币。Gas和以太币被故意分开,因为gas单位与具备自然成本的运算单位一致,而以太币的价格通常会由于市场力量产生波动。二者由自由市场调和:gas价格实际上由矿工决定,矿工可以拒绝以低于最低限度的gas价格进行交易。为了获得gas,你只需要向账户中添加以太币。以太坊客户端会自动为你的以太币购买gas,数量是你指定的交易最大支出。

在合约或交易执行的每个运算步骤,以太坊协议都要收费,以防止以太坊网络上发生蓄意攻击或滥用。每个交易都必须包含一个gas限度和每gas愿意支付的花费。矿工可以选择是否将交易包括在内和收集花费。如果交易产生的、用于运算步骤的gas总量,包括原始消息和可能引发的子消息,少于或等于gas限额,那么交易就会进行。如果gas总量超过gas限额,那么所有的变化都复原,但是交易仍然有效,矿工仍然可以收集花费。未用于交易执行的、所有多余的gas都会以以太币的形式偿还给发送方。不必担心超支,因为只会对你消费的gas收费。这意味着以高于预估的gas限额发送交易也是有效和安全的。

估算交易成本

交易花费的以太币总量基于两个因素:

gasUsed 是交易消费的gas总量

gasPrice 交易中指定的一个gas单元的价格(换算成以太币)

总成本= gasUsed * gasPrice

gasUsed

以太坊虚拟机上的每个操作都会被指派消费的gas数量。gasUsed是所有执行的操作所需的gas总额。有个电子表格可以看到背后的一些统计。

对于估算gasUsed,可以用estimate Gas API但是有些警告说明。

gasPrice

用户建构并签署交易,每个用户可以说明自己想要的gasPrice,可以是零。然而Frontier发布的以太坊客户端默认gasPrice是0.05e12 wei。由于矿工会使收入最优化,如果大部分交易都以0.05e12 wei 的gasPrice提交,就很难说服矿工接受价格更低或为0的交易。

示例交易成本

我们来做一个只添加2个数字的合约。EVM OPCODE ADD消费3 gas。

大概的成本,以默认gas价格计算 (2016年1月)是:

3 * 0.05e12 = 1.5e11 wei

1以太币是1e18 wei,总成本就是0.00000015以太币。

这是个简化的计算,因为忽略了一些成本,比如将2个数字转移给合约的成本,在他们可以被添加之前。

  • question
  • gas费用
  • gas成本计算器
  • 以太坊Gas价格

账户交互示例 — 投注合约

之前提到过,有两种类型的账户:

  • 外部账户 (EOA):由私钥控制的账户,如果你有和外部账户相关的私钥,就能从账户发送以太币和消息。
  • 合约: 有自己代码的账户,受代码控制。

以太坊默认的执行环境是没有生命的,什么都不会发生,每个账户的状态保持相同。但是,每个用户都可以通过从外部账户发送交易来触发行动,启动以太坊。如果交易的目的地是其他外部账户,交易可能会转移一些以太币,否则什么也不会做。但如果目的地是个合约, 反之合约会激活,自动运行代码。

代码有能力读/写自己的内部存储(一个将32字节钥匙映射到32字节价值的数据库),阅读存储的接收消息,给其他合约发送消息,转而触发执行。一旦执行停止,合约发送的消息所触发的所有的子执行都会停止(这些都以决定好的同步的顺序发生,比如,子调用在父调用进一步之前完全完成),执行环境立即再次停止,直到被下一个交易唤醒。

合约通常服务于四个目的:

  • 保持数据库代表着对其他合约或外部世界有用的东西;一个例子是合约激励货币,另一个例子是合约在特定的组织里记录会员。
  • 作为某种具有更复杂访问政策的外部账户,被称为“前向合约”,典型地只在特定条件下,把进来的消息转发给到指定目的地;例如,前向合约可能会等到指定3个私钥中的2个都确认了特定的消息之后才会进行转发(例如,多重签名)。更复杂的前向合约基于要发送的消息会有不同的条件。最简单的一个功能使用案例就是撤回限制,在一些更复杂的访问政策中难以驾驭。钱包合约就是个很好的例子。
  • 在多个用户之间管理一个正在进行的合约或关系。例子包括金融合约,有特定中介的第三方保管合约,或一些保险。也可以是开放合约,一方对其他方的随时参与保持开放;一个例子是自动给提交数学问题有效解决方案或是证明提供了一些运算资源的人发奖金的合约。
  • 给其他合约提供功能,本质上作为软件库。 合约通过被交替叫做“调用”或“发送消息”的活动进行互动。“消息”是包含一定量以太币,任何大小的数据字节串,发送方和接收方地址的事物。合约接收消息时,可以选择返还一些数据,消息本来的发送方可以立即使用。 这样发送消息就和调用一个功能一样。

因为合约有这样的作用,我们期望合约可以彼此互动。举个例子,设想一个情景,Alice和Bob赌100 Gav币,明年旧金山的温度不会超过35ºC。但是Alice非常有安全意识,她的第一个账户使用的前向合约,只有在3个私钥中的2个都批准的情况下才可以发送消息。Bob偏执于量子加密图形,他使用的前向合约,只传递有Lamport签名和传统ECDSA的消息(但是因为他很老派,所以更偏向于用基于SHA256的Lamport签名版本,以太坊不直接支持)。

投注合约本身需要从一些合约中取得旧金山天气的数据,当它想要实际发送Gav币给Alice或Bob时,也需要和Gav币合约交谈(或者,更准确地说,Alice或Bob的前向合约)。因次我们可以这样表示账户之间的关系:

Bob 想最终决定赌注的时候,就会发生以下的步骤:

  1. 交易被发出,触发消息从Bob的外部账户发送到他的前向合约。
  2. Bob的前向合约给合约发送消息散表和Lamport签名,发挥Lamport签名确认库的作用。
  3. Lamport签名确认库看到Bob想要基于SHA256的Lamport签名,于是给SHA256库多次发调用来确认签名。
  4. Lamport签名确认库一旦回到1,表明签名已确认,他就会给代表赌注的合约发送消息。
  5. 赌注合约检查提供旧金山天气的合约,查看天气如何。
  6. 赌注合约看到对消息的回应显示天气高于35ºC,就会给Gav币合约发送消息,将Gav币从它的账户转移到Bob的前向合约。

注意Gav币在Gav币合约的数据库中作为一个整体“储存”;第6步语境中“账户”的意思只是说在Gav币合约储存中有数据入口,有钥匙可以进入赌注合约的地址和余额值。接收到消息后,Gav币合约值上减少,与Bob前向账户对应的入口值增加。 我们可以在下表看到这些步骤:

离线签署交易

[可以把这一部分加到常见问题,指向turb以太坊向导的ethkey章节]

  • Resilience Raw Transaction Broadcaster

下一篇文章我们将会介绍《以太坊连载(22):深入浅出智能合约》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(20):如何使用GPU和矿池挖矿?

GPU挖掘

硬件

算法是内存难解的,为了使DAG适合内存,每个GPU需要1-2GB内存,如果你得到错误提示:Error GPU mining. GPU memory fragmentation? 说明你没有足够的内存。GPU挖矿软件是基于OpenCL实现的,AMD GPU会比同一水准的NVIDIA GPU更快。ASIC和FPGA相对低效因而被阻拦。要给芯片集成平台获取openCL,尝试:

  • AMD SDK openCL
  • NVIDIA CUDA openCL

Ubuntu Linux设置

对于这个快速指南,你会需要Ubuntu 14.04或15.04以及fglrx图像驱动器。你也可以使用NVidia驱动器和其他平台,但是你必须要找到自己的方式来获得有效的OpenCL安装,比如Genoil的ethminer分叉。

如果你在用15.04,到“软件与更新〉额外的驱动器”设置为“从fglrx为AMD图形加速器使用视频驱动器”。

如果你在用14.04,到“软件与更新〉额外的驱动器”设置为“从fglrx为AMD图形加速器使用视频驱动器”。很遗憾,对于一些人来说,这种方法可能不管用,因为Ubuntu 14.04.02中有个已知的程序错误会阻止你转换到GPU挖矿所必须的专属图形驱动器。

所以,如果你遇到这个程序错误,先到“软件与更新〉更新”选择“预发行的可靠更新提议”。然后,回到“软件与更新〉额外的驱动器”设置为“从fglrx为AMD图形加速器使用视频驱动器”。重启之后,值得检查一下现在确实正确安装了驱动器(例如通过再到“额外驱动器”)。

不管做什么,如果你在用14.04.02,一旦安装之后,就不要改变驱动器或者驱动器配置。例如,aticonfig –initial的使用(尤其是-f, –force选项)会“破坏”你的设置。如果你偶然改变了配置,会需要卸载驱动器,重启,再次安装驱动器并重启。

Mac设置

1
2
3
4
5
wget http://developer.download.nvidia.com/compute/cuda/7_0/Prod/local_installers/cuda_7.0.29_mac.pkg
sudo installer -pkg ~/Desktop/cuda_7.0.29_mac.pkg -target /
brew update
brew tap ethereum/ethereum
brew reinstall cpp-ethereum --with-gpu-mining --devel --headless --build-from-source

查看冷却状态:

1
aticonfig --adapter=0 --od-gettemperature

Windows设置

下载最新的Eth++安装,在安装界面的“选择组件”页面选择ethminer。

用geth使用ethminer

1
2
3
4
geth account new // Set-up ethereum account if you do not have one
geth --rpc --rpccorsdomain localhost 2>> geth.log &
ethminer -G // -G for GPU, -M for benchmark
tail -f geth.log

ethminer在端口8545(geth的默认RPC端口)和geth沟通。你可以通过给geth—rpcport选项来改变这种情况。ethminer会在任何端口发现geth。注意你需要用—rpccorsdomain localhos设置CORS标题。你也可以用-F http://127.0.0.1:3301 在ethminer设置端口。如果你想要在同一个电脑上挖几个实例,设置端口是必需的,尽管有些没有意义。如果你在私有链上测试,我们推荐你用CPU挖掘代替。

注意:你不需要把—mine选项给geth,或者在控制台开启挖矿,除非你想要在GPU挖掘顶端做CPU挖掘。

如果ethminer的默认无效,试试用—opencl-device X来规定OpenCL装置,其中X是{0, 1, 2,…}。用-M(基础测试程序)运行ethminer时,你会看到这样的文字:

1
2
Benchmarking on platform: { "platform": "NVIDIA CUDA", "device": "GeForce GTX 750 Ti", "version": "OpenCL 1.1 CUDA" }
Benchmarking on platform: { "platform": "Apple", "device": "Intel(R) Xeon(R) CPU E5-1620 v2 @ 3.7

为geth排错:

1
geth --rpccorsdomain "localhost" --verbosity 6 2>> geth.log

为矿工排错:

1
2
make -DCMAKE_BUILD_TYPE=Debug -DETHASHCL=1 -DGUI=0
gdb --args ethminer -G -M

注意:GPU挖矿时,散列率信息在geth上不可用。

用ethminer检查散列率,miner.hashrate总会报告0。

用eth使用ethminer

在单独的GPU上挖矿

为了在单独的GPU上挖矿,只需要用以下参数运行eth:

1
eth -v 1 -a 0xcadb3223d4eebcaa7b40ec5722967ced01cfc8f2 --client-name "OPTIONALNAMEHERE" -x 50 -m
  • -v 1 将冗长的信息设置为1。不要被信息刷屏。
  • -a YOURWALLETADDRESS 设置挖矿奖励会去的coinbase。以上地址只是一个例子。这一参数十分重要,确保不要在钱包地址出错,否则会接收不到以太币支出。
  • —client-name “OPTIONAL” 设置可选择的客户端名称,在网络上确定身份。
  • -x 50 请求大量的端点。帮助在开始找到端点。
  • -m on 在挖矿开启的状态下实际启动。
  • -G 打开GPU挖掘。

客户端运行时,你可以用geth附属或[ethconsole]和它互动(https://github.com/ethereum/ethereum-console)。

在多个GPU上挖矿

用多个GPU和eth挖矿与用geth和多个GPU挖矿十分相似。确保eth节点和正确设置的coinbase地址一起运行: eth -v 1 -a 0xcadb3223d4eebcaa7b40ec5722967ced01cfc8f2 —client-name “OPTIONALNAMEHERE” -x 50 -j

注意我们也添加了-j参数以使客户端有可用的JSON-RPC服务器与ethminer实例沟通。此外由于ethminer可以为我们挖矿,我们移除了与挖矿相关的参数。每个GPU都会执行一个不同的ethminer实例:

1
ethminer --no-precompute -G --opencl-device X

X是索引号码,与你想ethminer用{0, 1, 2,…}的OpenCL装置一致。为了轻松获取OpenCL装置列表,你可以执行ethminer —list-devices,它会提供一个OpenCL可以检测到的所有装置,以及每个装置的一些附加信息。

下面是一个样本输出:

1
2
3
4
5
[0] GeForce GTX 770
CL_DEVICE_TYPE: GPU
CL_DEVICE_GLOBAL_MEM_SIZE: 4286345216
CL_DEVICE_MAX_MEM_ALLOC_SIZE: 1071586304
CL_DEVICE_MAX_WORK_GROUP_SIZE: 1024

最终—no-precompute参数请求ethiminers不要提前创建下一个epoch的DAG。尽管不推荐这样,因为每次epoch过渡的时候,你都会有一个挖矿中断。

基准测试程序

挖矿能力通常以内存带宽衡量。我们的实现写在OpenCL上,很典型地在NVidia上被AMD GPU支持得更好。实验证据确认了在价格方面,AMD GPU比对应的NVidia挖矿表现更好。

用基准程序测试单一装置设置,你可以在基准测试程序模式下通过-M使用ethminer。

1
ethminer -G -M

如果你有很多装置,你会喜欢分别用基准程序测试,可以用–opencl-device选项,与之前章节相似: ethminer -G -M —opencl-device X 用ethminer —list-devices来列出可能的数字替代X {0, 1, 2,…}。 开始在Windows上挖矿,首先要下载geth windows binary。

  • 解压缩Geth (单击右键选择打开),启用命令提示符。用cd 导航到 Geth数据文件夹的位置(例如cd / 到C: 盘)
  • 输入geth —rpc开启geth。 进入以后,以太坊区块链会开始下载。有时候防火墙肯能会阻止同步进程(阻止时会有提示)。如果被阻止,点击“允许进入”。
  • 首先下载安装ethminer, C++挖矿软件 (防火墙或Windows本身可能会有反应,允许进入)
  • 打开另一个命令提示符 (保持第一个运行!)输入cd/Program\ Files/Ethereum(++)/release改变目录。
  • 确保eth完成区块链同步。如果同步不再进行,就可以在命令提示符输入ethminer -G开启挖矿进程。

此时可能会出现一些问题。如果有错误发生, 可以输入Ctrl+C来中断矿工。如果错误显示(提示)“内存不足”,就说明没有足够的GPU内存来挖以太币。

矿池挖矿

矿池挖矿是旨在通过联合参与矿工的挖矿力来解决预期收益问题的合作社(挖矿的矿工的算力来解决预期收益问题的合作组织)。作为回报,通常收取0-5%的挖矿奖励。挖矿池从中央账户用工作量证明提交区块并按照参与人贡献的挖矿力比例来重新分配奖励。

警告:大多数挖矿池包含第三方,中心组件,意味着他们是不需信任的。换言之,挖矿池操作人可以把你的收入拿走。谨慎操作。有很多具备开源数据库、不需信任的、去中心化的挖矿池。

警告:挖矿池只会外包工作量证明运算,他们不会使区块生效或运行虚拟机来检查执行交易带来的状态过渡。 这能有效地使挖矿池在安全方面像单个节点一样表现,他们的增长会造成51%攻击的中心化威胁。确保遵守网络能力分配,不要让挖矿池长得太大。

矿池

  • coinotron
  • nanopool
  • ethpool — 可预测的单独挖矿,非常规支出机制,附属于etherchain.org。
  • supernova
  • coinmine.pl
  • eth.pp.ua
  • talkether — 非常规支出机制,部分去中心化
  • weipool
  • ethereumpool
  • pooleum
  • alphapool
  • cryptopool
  • unitedminers
  • dwarfpool — 尽量避免(目前超过网络的50%)
  • laintimes — 停止使用

挖矿相关资源汇总

  • 过去24小时以太币链上领先的矿工
  • 2015年8月挖矿池散表率分配
  • 论坛上未维护的挖矿池列表
  • cryptocompare上的挖矿盈利能力计算器
  • cryptowizzard上的挖矿盈利能力计算器
  • etherscan上的挖矿盈利能力计算器
  • In The Ether上的挖矿盈利能力计算器
  • etherscan上的挖矿难度表

POS vs POW

参考资料:

文章中的列表对应的链接可以参考《Ethereum Homestead Documentation》第67页1.6.4 GPU mining

下一篇文章我们将会介绍《以太坊连载(21):账户、交易核心概念及投注合约解析》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(19):如何使用CPU挖矿?

CPU挖掘

你可以用电脑的中央处理器(CPU)挖以太币。自从GPU矿工的效率高出两个数量级,它就不再盈利了。然而你可以用CPU挖掘在Morden测试网或私有链上挖矿,以便创建你测试合约和交易所需要的以太币, 而无需花费实时网络上的真实以太币。

注意:测试网以太币除了用于测试目的外没有其他价值(查看测试网络)。

使用geth

用geth启动以太坊节点时,并不是默认挖掘。在CPU挖掘模式开启,你会用—mine命令行选项。-minerthreads参数可以用于设置平行于挖掘线程的数量(默认为处理器核心的总数)。

1
geth --mine --minerthreads=4

你也可以在执行期间用控制台开启或停止CPU挖掘。miner.start取一个矿工线程数量的可选参数。

1
2
3
4
> miner.start(8)
true
> miner.stop()
true

注意挖掘真实以太币只有在你与网络同步时才有意义(由于你是在共识区块顶部挖矿)。因此以太区块链下载器/同步器会延迟挖掘直到同步完成,此后挖掘自动开始,除非你用miner.stop()取消挖矿。

为了赚取以太币,你必须有etherbase(或coinbase)地址集。这个etherbase默认为你的第一个账户。如果你没有etherbase地址,geth –mine就不会开启。

你可以在命令行重新设置etherbase:

1
2
geth --etherbase 1 --mine 2>> geth.log // 1 is index: second account by creation order OR
geth --etherbase '0xa4d8e9cae4d04b093aac82e6cd355b6b963fb7ff' --mine 2>> geth.log

你也可以在控制台重新设置etherbase:

1
miner.setEtherbase(eth.accounts[2])

注意你的etherbase不必是本地账户地址,只要是现存的就可以。

有一个给你挖掘过的区块添加额外数据的选项(只有32字节)。按照惯例,它被解释为统一码字符串,你可以设置短期虚荣标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
miner.setExtra("ΞTHΞSPHΞΞ")
...
debug.printBlock(131805)
BLOCK(be465b020fdbedc4063756f0912b5a89bbb4735bd1d1df84363e05ade0195cb1): Size: 531.00 B TD: 643485290485 {
NoNonce: ee48752c3a0bfe3d85339451a5f3f411c21c8170353e450985e1faab0a9ac4cc
Header:
[
...
  Coinbase: a4d8e9cae4d04b093aac82e6cd355b6b963fb7ff
  Number: 131805
  Extra: ΞTHΞSPHΞΞ
...
}

你可以用miner.hashrate检查散表率,结果用H/s表示(每秒散表操作)。

1
2
> miner.hashrate
712000

成功挖掘一些区块以后,你可以检查etherbase账户中的以太币余额。现在假定你的etherbase是个本地账户:

1
2
> eth.getBalance(eth.coinbase).toNumber();
'34698870000000'

为了花费你赚的gas来交易,你需要解锁账户。

1
2
3
> personal.unlockAccount(eth.coinbase)
Password
true

你可以在控制台上用以下代码片段,检查哪个区块被特殊的矿工(地址)挖掘过:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function minedBlocks(lastn, addr) {
  addrs = [];
  if (!addr) {
    addr = eth.coinbase
  }
  limit = eth.blockNumber - lastn
  for (i = eth.blockNumber; i >= limit; i--) {
    if (eth.getBlock(i).miner == addr) {
    addrs.push(i)
    }
  }
  return addrs
}
// scans the last 1000 blocks and returns the blocknumbers of blocks mined by your coinbase
// (more precisely blocks the mining reward for which is sent to your coinbase).
minedBlocks(1000, eth.coinbase);
//[352708, 352655, 352559]

请注意,发现一个区块但是不能把它变成典型链会经常发生。这意味着你在当地把挖过的区块包括在内,当前的状态会显示归于你账户的挖矿奖励,然而不久后,会发现更好的链,我们转换到不包含你区块的链,因而不会记入任何挖矿奖励。因此很有可能矿工监控coinbase余额的时候会发现,它发生了相当程度的浮动。

下一篇文章我们将会介绍《以太坊连载(20):如何使用GPU挖矿?》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(18):什么是挖矿和Ethash算法?

挖矿简介

挖矿这个词源于对加密货币与黄金的类比。黄金或贵金属很稀有,电子代币也是,增加总量的唯一方法就是挖矿。以太坊也是这样,发行的唯一办法就是挖矿。但是不像其他例子,挖矿也是通过在区块链中创建、验证、发行和传播区块来保护网络的方法。

  • 挖以太币=保护网络=验证计算

什么是挖矿?

以太坊,和所有区块链技术一样,使用激励驱动的安全模式。共识基于选择具有最高总难度的区块。矿工创造区块,其他人检测有效性。区块只有在包含特定难度的工作量时才有效,还有其他合格性条件。请注意到以太坊Serenity里程碑,可能就会被取代(参考权益证明模型)。

以太坊区块链在很多方面与比特币区块链类似,但也有些不同。在区块链架构方面,以太坊和比特币之间最主要的的区别是,不像比特币,以太坊区块不仅包含交易列表也包含最近状态(merkle patricia特里结构的根散表编码在状态中更精确)除此之外,另外两个值,区块数和难度,也储存在区块中。

使用的工作量证明算法叫Ethash(Dagger-Hashimoto算法的改良版本),包括找到算法的随机数输入以使结果低于特定的难度阈值。工作量证明算法的意义在于,要找到这样一个随机数,没有比列举可能性更好的策略,而解决方法的验证琐碎又廉价。由于输出有均匀分布(是散表功能应用的结果),我们可以保证,平均而言,需要找到这样一个随机数的时间取决于难度阈值。这使得只通过操纵难度来控制找到新区块的时间成为可能。

正如协议中所描述的,难度动态调整的方式是每15秒整个网络会产生一个区块。我们说网络用15秒区块时间生产一个区块链。这个“心跳”基本上主要强调系统状态同步,保证不可能维持一个分叉(允许double spend)或被恶意分子重写历史,除非攻击者有半数以上的网络挖矿能力(即所谓的51%攻击)。

任何参与到网络的节点都可能是矿工,预期的挖矿收益和他们的(相对)挖矿能力或者说成正比,比如被网络总散表率标准化的,每秒尝试的随机数数量。

Ethash工作量证明是内存难解的,这使它能抵抗ASIC。内存难解性由工作量证明算法实现,需要选择依靠随机数和区块标题的固定资源的子集合。这个资源(几十亿字节大小的数据)叫做DAG。每3000个区块的DAG完全不同,125小时的窗口叫做epoch(大约5.2天),需要一点时间来生成。由于DAG只由区块高度决定,它可以被事先生成,如果没有被事先生成,客户端需要等到进程最后来生产区块。如果客户端没有预生成并提前缓存DAG,网络可能会在每个epoch过渡经历大规模区块延迟。注意不必要生成DAG以验证工作量证明,它可以在低CPU和小内存的状态下被验证。

在特殊情况下,从零开始创建节点的时候,只有在为现存epoch创建DAG的时候才会开始挖矿。

挖矿奖励

获奖区块的成功工作量证明矿工会获得:

  • “获胜”区块的静态区块奖,包含5.0(5个)以太币
  • 区块内支出的gas成本 — 一定数量的以太币,取决于当前gas价格
  • 叔伯块的额外奖励,形式是每个叔伯块包含额外的1/32

在区块中执行所有交易所消费的、由获胜矿工提交的gas都由每个交易的发送者支付。已发生的gas成本归到矿工账户作为共识协议的一部分。随着时间变化,这会使数据区块奖变得矮小。

叔伯块是稳定的区块,比如说,和包含先前区块(最多回6个区块)的父区块。有效的叔伯块会受到奖励以中和网络滞后给挖矿奖励带来的影响,因而提升安全性(这叫做GHOST协议)。叔伯块由成功工作量证明矿工形成的区块中所包含的叔伯块接收7/8的数据区块奖励(=4.375以太币)。每个区块最多允许2个叔伯块。

  • reddit上的叔伯块ELI5
  • 解释叔伯块的分论坛

挖矿的成功取决于设定的区块难度。区块难度动态调整每个区块,以规定网络散列能力来创造12秒区块时间。找到区块的机会因此由与难度相关的散列率产生。

Ethash DAG

Ethash将DAG(有向非循环图)用于工作量证明算法,这是为每个epoch生成,例如,每3000个区块(125个小时,大约5.2天)。DAG要花很长时间生成。如果客户端只是按需要生成它,那么在找到新epoch第一个区块之前,每个epoch过渡都要等待很长时间。然而,DAG只取决于区块数量,所以可以预先计算来避免在每个epoch过渡过长的等待时间。Geth和ethminer执行自动的DAG生成,每次维持2个DAG以便epoch过渡流畅。挖矿从控制台操控的时候,自动DAG生成会被打开和关闭。如果geth用—mine选项启动的时候,也会默认打开。注意客户端分享DAG资源,如果你运行任何客户端的多个实例,确保自动的DAG生成只在一个实例中打开。

为任意epoch生成DAG:

1
geth makedag <block number> <outputdir>

实例geth makedag 360000 ~/.ethash.。请注意ethash为DAG使用~/.ethash (Mac/Linux) 或~/AppData/Ethash (Windows),这样它可以在不同的客户端实现以及多个运行实例中分享。

算法

我们的算法,Ethash(之前被称为Dagger-Hashimoto),是基于一个大的、瞬时的、任意生成的、形成DAG(Dagger-part)的资料组规定,尝试解决它一个特定的约束,部分通过区块标题散列来决定。

它被设计用于在一个只有慢CPU的环境中来散列快速验证时间,但在被提供大量高带宽内存时,为挖矿提供大量的加速。大量内存需求意味着大规模矿工获得相对少的超线性利益。高带宽需求意味着从堆在很多超速处理单元、分享同样内存的加速在每个单独的单元给出很少的利益(译者注:通过阻止专用芯片共享内存的方式,降低矿机的作用)。

没有节点验证的利益因而阻碍中心化,这在挖矿中很重要。

外部挖矿应用和以太坊工作规定和报送的后台程序之间的交流通过JSON-RPC API发生。提供两个RPC功能;eth_getWork和eth_submitWork。

这些被正式记录在JSON-RPC API维基百科文章的矿工条目下。

为了挖矿你需要一个完全同步的、能够挖矿的以太坊客户端和至少一个以太坊账户。这个账户用于发送挖矿奖励,通常被称为货币基或以太基。查看这个说明的“创建帐户”章节,学习如何创建帐户。

警告:开始挖矿前,确保区块链和主链完全同步,否则就不能在主链上挖矿。

下一篇文章我们将会介绍《以太坊连载(19):如何使用CPU挖矿?》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(17):搭建测试网络和私有链

测试网络

Morden测试网

Morden是公开的以太坊替代测试网。它会贯穿于整个软件里程碑Frontier和Homestead。

用法

eth (C++客户端) 0.9.93及以上版本自动支持。比如开启以下任意客户端时,通过—morden参数。

PyEthApp (Python客户端) PyEthApp支持v1.0.5以后的morden网络。

geth (Go客户端)

细节

除以下几条,所有参数都和主要的以太坊网络相同:

  • 网络名称:Morden
  • 网络身份:2
  • genesis.json(如下);
  • 初始账户随机数(IAN)是220 (不像之前的网络中是0)

– 状态树形结构中的所有账户都有随机数>= IAN。

– 账户被插入到状态树形结构中时,都会被赋予一个初始随机数= IAN。

  • 初始通用区块哈希值: 0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303
  • 初始通用状态根:f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9

Morden的genesis.json

获取Morden测试网以太币

有两种方法可以获取Morden测试网以太币:

  • 用CPU/GPU挖矿(参见挖矿)。
  • 用以太坊wei龙头。

设置本地私有测试网

eth (C++ 客户端)

可以使用–genesis和–config连接到或创建一个新的网络。

可以同时使用–config和–genesis。

那样的话,–config提供的初始区块描述会被–genesis选项覆盖。

注意:包含一个网络的JSON描述。

  • sealEngine (用来在区块挖矿的引擎)

    “Ethash”是以太坊工作量证明引擎(用于实时网络)。

    “NoProof” 在区块挖矿不需要工作量。

  • params (诸如minGasLimit, minimumDifficulty, blockReward, networkID等一般的网络信息)

  • genesis (初始区块描述)
  • accounts (设置包含账户/合约的初始状态)

这是一个Config的例子(用于Olympic网络):

注意:包含一个网络的JSON描述。

内容与’config’参数提供的初始领域相同。

geth (Go客户端)

你可以在私有测试网上生成或挖掘自己的以太币。这个试验以太坊方法很划算,可以避免不得不挖矿,或找到Morden测试网络的以太币。

在私有链中需要详细说明的事件有:

  • 定制初始文件
  • 定制数据目录
  • 定制网络ID
  • (推荐) 废弃节点发现

初始文件

初始区块是区块链的起始 — 第一个区块,区块0,唯一没有指向前面区块的一个区块。协议确保其他节点不会和你的区块链一致,除非他们和你有相同的初始区块,这样你想创建多少私有测试网区块链,就可以创建多少!

1
2
3
4
5
6
7
{
"nonce": "0x0000000000000042", "timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x0", "gasLimit": "0x8000000", "difficulty": "0x400",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x3333333333333333333333333333333333333333", "alloc": { }
}

存储文件为CustomGenesis.json。用下面的标志启动geth节点的时候,你会引用到这个。

1
--genesis /path/to/CustomGenesis.json

私有网络的命令行参数

有一些必需的命令行选项(又称为“标志”)来确保你的网络是私有的。我们已经谈到了初始标志,下面还有几个。注意所有下面的指令都会用在geth以太坊客户端。

1
--nodiscover

使用这个命令可以确保你的节点不会被非手动添加你的人发现。否则,你的节点可能被陌生人的区块链无意添加,如果他和你有相同的初始文件和网络ID。

1
--maxpeers 0

如果你不希望其他人连接到你的测试链,可以使用maxpeers 0。反之,如果你确切知道希望多少人连接到你的节点,你也可以通过调整数字来实现。

1
--rpc

这个指令可以激活你节点上的RPC界面。它在geth中通常被默认激活。

1
--rpcapi "db,eth,net,web3"

这个命令可以决定允许什么API通过RPC进入。在默认情况下,geth可以在RPC激活web3界面。

重要信息:请注意在RPC/IPC界面提供API,会使每个可以进入这个界面(例如dapp’s)的人都有权限访问这个API。注意你激活的是哪个API。Geth会默认激活IPC界面上所有的API,以及RPC界面上的db,eth,net和web3 API。

1
--rpcport "8080"

将8000改变为你网络上开放的任何端口。Geth的默认设置是8080.

1
--rpccorsdomain "http://chriseth.github.io/browser-solidity/"

这个可以指示什么URL能连接到你的节点来执行RPC定制端任务。务必谨慎,输入一个特定的URL而不是wildcard ( * ),后者会使所有的URL都能连接到你的RPC实例。

1
--datadir "/home/TestChain1"

这是你的私有链数据所储存在的数据目录(在nubits下)。选择一个与你以太坊公有链文件夹分开的位置。

1
--identity "TestnetMainNode"

这会为你的节点设置一个身份,使之更容易在端点列表中被辨认出来。这个例子说明了这些身份如何在网络上出现。

发布geth

你创建了定制初始区块JSON并建立区块链数据目录后,在控制台输入以下指令,进入geth:

1
geth --identity "MyNodeName" --genesis /path/to/CustomGenesis.json --rpc --rpcport "8080" --rpcco

注意:请改变标志与定制设置匹配。

每次想要进入定制链的时候,你都需要用定制链指令启动geth实例。如果你只在控制台输入“geth”,它不会记住你设置的所有标志。

给账户预分配以太币

“0x400”难度能让你再私有测试网链上快速挖以太币。如果你创建了自己的链,开始挖矿,你应该几分钟就会有上百个以太币,远远超过了在网络上测试交易所需的数量。如果你还想给账户预分配以太币,就需要:

  1. 创建私有链以后再创建新的以太坊账户。
  2. 复制新的账户地址。
  3. 在Custom_Genesis.json文件中添加以下指令:
1
2
3
4
5
"alloc":
{
"<your account address e.g. 0x1fb891f92eb557f4d688463d0d7c560552263b5a>":
{ "balance": "20000000000000000000" }
}

注意:用你的账户地址取代0x1fb891f92eb557f4d688463d0 d7c560552263b5a

保存初始文件,重新运行私有链指令。Geth完整装载以后,关闭它。

我们想指派一个地址给变量primary,查看它的余额。

在终端运行geth account list指令,查看指派给你的新地址账户号码是什么。

1
2
3
4
5
6
> geth account list

Account #0: {d1ade25ccd3d550a7eb532ac759cac7be09c2719}
Account #1: {da65665fc30803cb1fb7e6d86691e20b1826dee0}
Account #2: {e470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32}
Account #3: {f4dd5c3794f1fd0cdc0327a83aa472609c806e99}

记录你预分配以太币的账户号码。或者,可以用geth console(和最先启动geth时保持一样的参数)启动控制台。提示出现以后,输入

1
> eth.accounts

这会返回到你拥有的账户地址排列。

1
> primary = eth.accounts[0]

注意:用你的账户指数取代0,这个控制台指令会返回到你第一个以太坊地址。

输入以下指令:

1
> balance = web3.fromWei(eth.getBalance(primary), "ether");

这应该会返回到7.5,意味着你账户里有那么多以太币。我们必须在你初始文件的分区里放那么多数量是因为“余额”领域以wei为单位取一个数字,wei是以太坊货币以太币的最小面额(参见以太币)。

下一篇文章我们将会介绍《以太坊连载(18):什么是挖矿和Ethash算法?》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(16):公有链、联盟链、私有链及网络配置介绍

以太坊网络

去中心化共识的基础是参与节点的点对点网络,节点维护并保证区块链网络的安全。参见挖矿。

以太坊网络数据统计

EthStats.net是以太坊网络实时数据的仪表板,这个仪表板展示重要信息,诸如现在的区块,散表难度,gas价格和gas花费等。页面上显示的节点只是精选了网络上的实际节点。任何人都可以在EthStats仪表板上添加他们的节点。Github上的Eth-Netstats README描述了如何连接。

EtherNodes.com展示了节点数的当前和历史数据以及以太坊主网络和Morden测试网络上的其他信息。

当前实时网络上客户端实现分配 – EtherChain上的实时数据。

公有链、私有链和联盟链

当今大多数以太坊项目都依靠以太坊作为公有链,公有链可以访问到更多用户,网络节点,货币和市场。然而通常有理由更偏好私有链或联盟链(在一群值得信任的参与者中)。例如,银行领域的很多公司都希望以太坊作为他们私有链的平台。

以下是博客发文《关于公有链和私有链》的摘录,它解释了三种区块链在许可方面的区别:

  • 公有链:世界上所有人都可以阅读和发送交易。如果他们合法都有希望看到自己被包括在内。世界上任何人都能参与到共识形成过程——决定在链条上添加什么区块以及现状是怎样的。作为中心化或准中心化信任的替代品,公有链受加密经济的保护,加密经济是经济激励和加密图形验证的结合,用类似工作量证明或权益证明的机制,遵循的总原则是人们影响共识形成的程度和他们能够影响的经济资源数量成正比。这类区块链通常被认为是“完全去中心化“。

  • 联盟链:共识形成过程由预先选择的一系列的节点所掌控,例如,设想一个有15个金融机构的团体,每个机构都操作一个节点,为了使区块生效,其中的10个必须签署那个区块。阅读区块链的权利可能是公开的,或仅限于参与者,也有混合的路径,比如区块的根散表和应用程序编程接口一起公开,使公共成员可以进行一定量的查询,重获一部分区块链状态的加密图形证明。这类区块链被认为是“部分去中心化”。

  • 私有链:书写许可对一个组织保持中心化。阅读许可可能是公开的或者限制在任意程度。应用很可能包含对单个公司内部的数据库管理,审查等,因此公共的可读性在很多情况下根本不必要,但在另一些情况下人们又想要公共可读性。

私有链/联盟链可能和公有链毫无联系,他们仍然通过投资以太坊软件开发,对以太坊整体生态系统有利。经过一段时间,这会转变成软件改善,知识共享和工作机会。

如何连接

Geth会持续尝试在网络上连接到其他节点,直到有了端点为止。如果你在路由器上有可用的UPnP或者在面向因特网的服务器上运行以太坊,它也会接受其他节点的连接。

Geth通过发现协议找到对等端。在发现协议中,节点互相闲聊发现网络上的其他节点。最开始,geth会使用一系列辅助程序节点,这些辅助程序节点的端点记录在源代码中。

检查连接和ENODE身份

要检查客户端在交互控制台上连接了多少对等端点,net模块有两个属性可以提供信息,告诉你对等端点的数量以及你是否在监听的节点。

1
2
3
4
> net.listening
true
> net.peerCount
4

了解更多关于连接对等端点的信息,比如IP地址、端口号和支持协议,用管理员对象的peers()功能。admin.peers()会返回到现在已连接的对等端点列表。

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
> admin.peers
[{
ID: 'a4de274d3a159e10c2c9a68c326511236381b84c9ec52e72ad732eb0b2b1a2277938f78593cdbe734e6002bf23114d434a085d260514ab336d4acdc312db671b',
Name: 'Geth/v0.9.14/linux/go1.4.2',
Caps: 'eth/60',
RemoteAddress: '5.9.150.40:30301',
LocalAddress: '192.168.0.28:39219'
}, {
ID: 'a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c',
Name: 'Geth/v0.9.15/linux/go1.4.2',
Caps: 'eth/60',
RemoteAddress: '52.16.188.185:30303',
LocalAddress: '192.168.0.28:50995'
}, {
ID: 'f6ba1f1d9241d48138136ccf5baa6c2c8b008435a1c2bd009ca52fb8edbbc991eba36376beaee9d45f16d5dcbf2ed0bc23006c505d57ffcf70921bd94aa7a172',
Name: 'pyethapp_dd52/v0.9.13/linux2/py2.7.9',
Caps: 'eth/60, p2p/3',
RemoteAddress: '144.76.62.101:30303',
LocalAddress: '192.168.0.28:40454'
}, {
ID: 'f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0',
Name: '++eth/Zeppelin/Rascal/v0.9.14/Release/Darwin/clang/int',
Caps: 'eth/60, shh/2',
RemoteAddress: '129.16.191.64:30303',
LocalAddress: '192.168.0.28:39705'
} ]

要检查geth使用的端口,发现你自己的enode URI 执行:

1
2
3
4
5
6
7
8
9
10
11
> admin.nodeInfo
{
Name: 'Geth/v0.9.14/darwin/go1.4.2',
NodeUrl: 'enode://3414c01c19aa75a34f2dbd2f8d0898dc79d6b219ad77f8155abf1a287ce2ba60f14998a3a98c0cf14915eabfdacf914a92b27a01769de18fa2d049dbf4c17694@[::]:30303',
NodeID: '3414c01c19aa75a34f2dbd2f8d0898dc79d6b219ad77f8155abf1a287ce2ba60f14998a3a98c0cf14915eabfdacf914a92b27a01769de18fa2d049dbf4c17694',
IP: '::',
DiscPort: 30303,
TCPPort: 30303,
Td: '2044952618444',
ListenAddr: '[::]:30303'
}

更快下载区块链

启动以太坊客户端时,会自动下载以太坊区块链。用于下载以太坊区块链的时间会根据客户端、客户端设置、连接速度和可用的端点数量变化。下面是更快获取以太坊区块链的一些选项。

使用geth

如果你在用geth客户端,你可以做些什么来加速下载以太坊区块的时间。如果你用—fast标志来执行以太坊快速同步,不会保留过去的交易数据。

注意:你不能在执行所有或者部分正常的同步操作之后再使用这个标志,也就是说在用这个指令之前,不能下载以太坊区块链的任何部分。查看这个Ethereum Stack.Exchange answer了解更多。

下面是想要更快同步客户端时使用的一些标志。

—fast

这个标志使通过状态下载而不是下载整个区块数据来实现快速同步成为可能。这样也能大幅减少区块链尺寸。注意:—fast只在从头开始同步区块链,并且是出于安全原因第一次下载区块链时,才会运行。查看Reddit发文了解更多。

—cache=1024

分配到内部缓存的千兆内存(最少 16MB / 数据库)。默认是16MB,所以根据你电脑内存多少,增加到256, 512, 1024 (1GB)或者2048 (2GB)会带来不同。

—jitvm 这个标志可以激活JIT VM。

完整的控制台命令示例:

1
geth --fast --cache=1024 --jitvm console

了解更多关于快速同步和区块链下载次数的讨论,查看这篇Reddit发文。

导出/导入区块链

如果你已经同步了整个以太坊节点,可以从完全同步的节点中导出区块链数据并将其导入新节点。你可以在geth中用geth export filename指令导出所有节点,并用geth import filename将区块链导入节点,来实现这一目的。

静态节点,信任节点和启动节点

Geth支持一个叫静态节点的特征,如果你有特定的端点,你会一直想与静态节点连接。如果断开连接,静态节点会再次连接。你可以配置永久性静态节点,方法是将如下所说的放进/static-nodes.json(这应该是和chaindata以及keystone在同一个文件夹)

1
2
3
4
[
"enode://f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0@33.4.2.1:30303",
"enode://pubkey@ip:port"
]

你也可以在运行期间通过Javascript使用admin.addPeer()加入静态节点。

1
> admin.addPeer("enode://f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae

连接的常见问题

有时候可能无法连接,最常见的原因有:

  • 本地时间不正确。要参与到以太坊网络中,需要精确的时钟。检查OS如何同步时钟(例如sudo ntpdate -s time.nist.gov),即便只快了12秒也有可能导致0端点。
  • 有的防火墙配置可能会阻止UDP流通。可以用静态节点功能或者控制台上的admin.addPeer() 来手动配置连接。

不使用发现协议来启动geth,你可以用—nodiscover参数。你只会在运行测试节点或有固定节点的实验测试网络时才想要这样做。

下一篇文章我们将会介绍《以太坊连载(17):搭建私有链和测试网络》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。

以太坊连载(15):钱包、以太币、Gas介绍

在线钱包,纸钱包和离线存储

这只是链接和说明的集散地。请将它从列表模式转换到生态系统。这边举的例子,可能会解释偏执的实践,列出潜在风险。

  • Mist以太坊钱包

– 下载版本

– Mist以太坊钱包开发者预览-基础博客发文

– 如何简单地设置以太坊Mist钱包!- Tommy Economics教程

  • Kryptokit Jaxx

– Jaxx 主网站

– 手机版本

  • Etherwall

– Etherwall网站

– Etherwall源

  • MyEtherWallet

– MyEtherWallet网站

– MyEtherWallet源

– Chrome延伸

  • 离线存储

– ConsenSys的冰箱 – 基于综合了光源钱包和HD钱包库的离线存储

– Reddit discussion 1

– 如何设置离线存储钱包

  • Hardware钱包

– reddit discussion 2

– reddit discussion 3

  • Brain钱包

– brain钱包不安全,请不要使用。https://www.reddit.com/r/ethereum/comments/45y8m7/brain_wallets_are_now_generally_shunned_by/

– 对brain钱包要特别谨慎,请参考近期的争论:https://reddit.com/r/ethereum/comments/43fhb5/brainwallets vs http://blog.ether.camp/post/138376049438/why-brain-wallet-is-the-best

  • Misc

– Kraken钱包清理工具– 预售钱包导入

– 安全储存以太币的推荐方法

– 如何购买和储存以太币

– 向外行人介绍蛮力以及不要用brain钱包的原因

– Pyethsaletool

– 账号和钱包

发送以太币

以太坊钱包支持通过图像界面发送以太币。

以太币也可以用geth控制台转换。

1
2
3
4
> var sender = eth.accounts[0];
> var receiver = eth.accounts[1];
> var amount = web3.toWei(0.01, "ether")
> eth.sendTransaction({from:sender, to:receiver, value: amount})

了解更多以太币转移交易,请参考账户类型,Gas和交易。

以太坊在加密货币领域是独一无二的,原因在于以太币作为加密燃料具有实用价值,通常被称作“gas”。除交易费用外,gas是每个网络请求的中心部分,需要发送者为消费的运算资源付费。Gas成本是基于请求规模和复杂性的动态计算,乘以现在的gas价格。它作为加密燃料的价值能够增加以太币和以太坊作为一个整体的稳定性和长期需求。了解更多信息,请参考账户类型,Gas和交易。

Gas和以太币

Gas被认为是网络资源/使用的固定成本。想要发送交易的真实成本保持一致,所以不希望gas发行,一般来说货币是不稳定的。因此我们发行以太币,它的价值会变动,但也会根据以太币来执行gas价格换算。如果以太币价格上升,gas价格换算成以太币会下降,以此来保持gas的真实花费相同。 gas有多个相关词汇:gas成本,gas限制和gas费用。gas背后遵循的原则是使以太坊网络上每个交易或计算成本保持稳定的价值。

  • gas成本是静态值,是以gas为单位的计算成本,目的是保持gas的真实价值不变,所以这个成本会一直稳定。

  • gas价格是以另一货币或代币比如说以太币为单位的gas成本。为了保持gas价值稳定,gas价格是浮动值,如果代币或货币成本波动,gas价格也会变化以保持同样的真实价值。Gas价格的设定是根据多少用户愿意花费和多少进程节点愿意接受的平衡价格。

  • Gas限制是每个区块能使用的gas最大限额,被视为计算工作量,交易量和区块大小的最大值,矿工可以随着时间慢慢改变这个值。

  • gas费用是运行一个特别的交易或程序(被称作合约)所需的gas。 一个区块的gas费用可以用来暗示计算工作量,交易量和区块大小。gas费用支付给矿工(或PoS中的担保承包人) 。

参考资料:

文章中的列表对应的链接可以参考《Ethereum Homestead Documentation》第54页1.4.4 Online wallets, paper wallets, and cold storage

下一篇文章我们将会介绍《以太坊连载(16):公有链、联盟链、私有链介绍及参数配置》

感谢朝夕团队Azure, Bob参与《Ethereum Homestead Documentation》的翻译和校验。