我将介绍区块链的工作原理。 我的解释与物理学家向你解释量子理论非常相似。
区块链上的任何交易都将广播到整个网络。其中一个节点准备一个块,交易发生在同一时间。该块被发送到整个网络时产生一个难题。难题是弄清楚交易在块中出现的顺序。单个计算机难以解决难题,需要反复试验或蛮力解决方案。网络中的一台计算机都可以在短时间内找出难题。那块被证实。网络中的两台计算机可能会同时解决这个难题(具有不同的顺序)。在这种情况下,两个块都会被传送到网络。
网络中的每个确认的块被链接到网络中的前一个块。有些时候,这些链可能会在个别节点发散。再次通过共识,随着时间的推移,较长的连锁胜出。因此,单个区块链就会成为真相的来源。
由于这些复杂的计算,区块链上的任何交易都需要一些时间来确认。如果交易被6个或12个后续块确认,那么它永远是区块链的一部分。虽然区块链是一种技术,但是以不同的技术的平台,实现方式也不尽相同。比特币和以太坊是区块链的两个流行实现。在比特币网络中,交易需要15分钟才能确认。而以太坊协议有一个简单的难题,所以一个交易只需要几秒钟来确认。
以太坊协议近来颇受欢迎。它在2013年向全世界宣布。它拥有一个良好的开发者生态系统。以太坊协议由许多程序实现。实施以太坊的流行程序之一就是Geth。它使用Go语言来实现。 如果你在你的系统上运行geth,它会下载整个公共区块链。 但实践中,我们喜欢创建自己的私人区块链,只在我们的系统上运行。 从官方来源下载Geth。 安装在Mac上的任何文件夹中。 并将该文件夹添加到$PATH变量中。
要创建一个私人区块链,我们需要初始化一个创世区块(第一个区块)。
{
"coinbase" : "0x0000000000000000000000000000000000000001",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x8000000",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"alloc": {},
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
}
}
geth --datadir=./chaindata/ init ./genesis.json
初始化 Geth 之后,就可以创建你的个人项目了。
geth --datadir=./chaindata/ init ./genesis.json
现在,geth 只在你的电脑上运行。 但是,以太坊公共链通过 geth 会运行在很多电脑上。 你随时可以自由地开始和停止。 如果 geth 启动,它将从网络中的其他节点下载最新的链式数据。 这样一来,区块链就真正分散了,没有一个节点控制网络。
在 Geth 初始化之后,运行 Geth 开始你的私人区块链。
区块链术语
我将通过以太坊的交易和区块来解释区块链中的术语。考虑如下一个交易:
以太坊的交易。
上边交易的属性有很多细节。From和To是公共链的两个账户。假设这两个账户分别是Joe和Mike,在这个交易中Joe将7.53个以太币或者3501.45美元转改Mike。当创建任何区块链账户的时候会生成一个公私钥对。这里不会说明加解密是怎样工作的,但是在上层你会和别人分享你的公钥,自己保存自己的私钥。私钥必须安全保存,如果私钥丢失就无法登陆到你的区块链账户,这一点很重要。交易中From和To属性代表区块链中两个账户(Joe和Mike)的公钥做哈希的值。
交易本身也有一个哈希值,并且该交易是块的一部分(4642361)。上边的交易记录里面有两个确认说明在区块链中这个块下边还有另外两个块。接着往下是属性Amount,以及一些属性和交易金额有关。每一次交易都需要计算和处理,所以每一次交易都要收费。当发起一次交易的时候会发送两个额外的参数燃料价格和燃料供给上限,燃料供给上限代表可提供的最大的计算,燃料价格代表每一次计算的价格,燃料价格和交易中燃料使用量的乘积就是交易费用。
你可能注意到燃料价格(每次计算的价格)用10GWei表示,Wei是一个以太币面值单位。
以太币面值。
一个以太币值10^18个Wei,值10^9个GWei,交易金额是10GWei乘以21000等于210000GWei或者0.00021以太币。
现在已经理解了交易属性,我们看一下块属性,考虑一个块如下:
以太链里边的块
我不会讲块的每一个属性,但是我会提到三个属性:难度值、矿工和奖励。当准备一个块的时候难度值表示挖这个块的难度。矿工就是一个为该块解谜的以太节点,该矿工获得该块里面所有交易费用。
挖矿行动
当打开Geth的时候会开启一个IPC终端,通过日志的最后一行可以检索该IPC终端。
INFO [11-29|13:12:06] IPC endpoint opened: /Users/vijayst/documents/react/vijay/blockchain/assignment_2/chaindata/geth.ipc
geth attach /Users/vijayst/documents/react/vijay/blockchain/assignment_2/chaindata/geth.ipc
miner.start(1);
上边的命令在一个线程里面开启了一个矿工。现在我们的节点已经参与到挖矿的过程中,挖矿就是确认交易。另外,挖矿也会产生以太币(coinbase)并且把该以太币添加到该节点的账户中。
我们通过钱包程序Mist创建主账户,Mist是一个基于电子Meteor应用。从官方源下载并安装该程序并且将安装路径添加到$PATH变量里面,安装路径通常是/Applications/Mist.app/Contents/MacOS。使用下面的命令启动Mist:
mist --rpc /Users/vijayst/documents/react/vijay/blockchain/assignment_2/chaindata/geth.ipc
在Mist里面创建一个账户会生成公私钥对并且当你启动挖矿的时候,你的账户里面会产生以太币。
Mist和主账户
我的账户里面有1245个以太币,这些是我的系统挖矿的奖励。不错,对吧?(这只适用于你的私有网络)
在JavaScript控制台里面调用miner.stop()停止挖矿。
使用React应用与区块链进行交互
我们开始准备写React应用程序,它将与区块链互动。 我们将继续使用我们的私人网络。 使用create-react-app创建一个新的react应用程序。
create-react-app blockchaindemo
cd blockchaindemo
yarn start
本地服务器从端口3000开始。如果我们导航到http//localhost:3000,就可以看到我们的React应用程序。
接下来,我们要在私有区块链上启动以太坊节点。 我提到以太坊节点,因为我们不打算使用Geth来进行开发。 Geth是一个CPU占用率很高的挖掘组件。 值得庆幸的是,以太坊的开发者已经构建了一个简单的ethereum节点来测试testrpc。
yarn global add ethereumjs-testrpc
使用testrpc --secure启动testrpc。 默认情况下,testrpc在沙箱环境中创建10个帐户。 它在
8545
端口中作为http服务器运行。
yarn add web3
yarn add web3@^0.19.0
让我们开始研究App组件。 导入web3。
import Web3 from "web3"
Web3更像一个API。 我们在componentDidMount生命周期方法中与API交互。 让我们先连接到testrpc。
componentDidMount() {
const provider = new Web3.providers.HttpProvider("http://localhost:8545");
const web3 = new Web3(provider);
}
componentDidMount() {
const provider = new Web3.providers.HttpProvider("http://localhost:8545");
const web3 = new Web3(provider);
const accounts = web3.eth.accounts.map(account => {
let balance = web3.eth.getBalance(account);
balance = web3.fromWei(balance, 'ether').toNumber();
return { account, balance };
});
this.setState({ accounts });
}
帐户收集地址。 如果我们使用getBalance函数,我们可以得到结果然后通过用.fromWei函数将其转换为以太坊。 余额仍然是对象格式。 toNumber函数将其转换为十进制。
最后,我们在组件中显示帐户余额。
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Blockchain Demo</h1>
</header>
<table border="1" cellpadding="8" cellspacing="0" style={{ border: '1px solid black', margin: 30 }}>
<thead>
<tr>
<th>Account</th>
<th>Balance</th>
</tr>
</thead>
<tbody>
{this.state.accounts.map(accountItem => (
<tr key={accountItem.account}>
<td>{accountItem.account}</td>
<td>{accountItem.balance}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
在testrpc的帐户余额
让我们再来看看我们的例子。我们将添加一个按钮。点击按钮,让我们从第一个账户转移10以太到第二个账户。
sendTransaction函数进行传输。我故意简化了它。
handleTransfer() {
const from = this.web3.eth.accounts[0];
const to = this.web3.eth.accounts[1];
const value = this.web3.toWei(10, "ether");
this.web3.eth.sendTransaction({ from, to, value });
}
通常,帐户处于锁定状态。我们必须使用web3.personal.unlockAccount函数来解锁它。使用-secure标志运行testrpc会锁定所有帐户。在撰写博客的时候,由于bug,unlockAccount不能正常工作。
在区块链中确认交易需要一些时间。通常几秒钟。使用testrpc并没有开始挖掘。但是我们可以使用-blocktime标志来模拟挖掘。确认我们的交易后,我们通常要刷新UI。但是,我们怎么知道交易已经确认。我们定期轮询区块链以获取交易对象。当我们得到它,我们刷新用户界面。
handleTransfer() {
const from = this.web3.eth.accounts[0];
const to = this.web3.eth.accounts[1];
const value = this.web3.toWei(10, "ether");
const txnHash = this.web3.eth.sendTransaction({ from, to, value });
const handle = setInterval(() => {
const txn = this.web3.eth.getTransaction(txnHash);
if (txn) {
clearInterval(handle);
this.refreshUI();
}
}, 100);
}
App.js的所有源代码都能在Github上面找到。
Contracts等
我们已经初步了解了区块链发展。以太坊还有更多东西等待挖掘。我们有一个叫Contracts的东西。Contracts可以部署在区块链上。它将拥有自己的地址,就像一个帐户。Contracts也可以用于以太坊。授权账户可以使用Contracts在区块链上启动交易。
Solidity是用于在区块链上创建新Contracts的编程语言。有一些工具可以编写Solidity代码。 Remix和Ethereum Studio是用于创建和部署Contracts的两种流行工具。对于JavaScript开发者来说,truffle是一个管理Contracts的NPM包。truffle也让我们编写测试用例来测试Contracts。
作为React开发人员,我们可能需要了解如何创建和部署Contracts。以及如何调用Contracts的功能来启动区块链上的交易。我现在不会再深入探讨Contracts了。但是,我正在寻找另一个使用区块链的案例进行研究,在另一个案例中,我将探索更多的Contracts。