以太坊开发:入门
介绍
在我之前的两篇文章中,我探讨了 Solidity 语言。该语言旨在与以太坊虚拟机 (EVM) 配合使用。在本文中,我们将先讲解语言理论,然后使用一个测试环境来测试我们的合约。通过这种方式,我们将能够更好地理解以太坊的工作原理。
工具
在第一篇文章中,我们将使用truffle和ganache-cli。Truffle 是一个以太坊开发框架。它允许你创建测试环境、为合约编写测试等等。但在本文中,我们仅使用它来创建测试环境。
ganache-cli将与 truffle 配合使用,创建一个功能齐全的测试环境。我们在这里所做的与实际生产区块链不太一样,但它能让我们了解其工作原理。
安装工具
- 松露:
[sudo] npm install -g truffle
- ganache-cli:
[sudo] npm install -g ganache-cli
准备工作
首先,我们将初始化一个新的 truffle 项目。为此,请创建一个新目录并在其中运行truffle init
:
现在你将有多个文件夹。首先,打开truffle-config.js并将其粘贴到其中:
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
networks: {
development: {
host: '127.0.0.1',
port: 7545,
network_id: '*'
}
}
}
对于 Windows 用户,您必须删除truffle.js文件以避免冲突。对于其他用户,您可以保留两者并将此代码放入truffle.js中,或者像 Windows 用户一样操作,这都无所谓。
该文件表明我们的开发网络将在 localhost:7545 上运行。
接下来,在contract文件夹中,创建一个新的DeveloperFactory.sol文件。我们的合约将写入此处。在文件中输入以下内容:
pragma solidity ^0.4.18;
contract DeveloperFactory {
// Let's create a Developer!
event NewDeveloper(uint devId, string name, uint age);
uint maxAge = 100;
uint minAge = 5;
struct Developer {
string name;
uint id;
uint age;
}
Developer[] public developers;
mapping (uint => address) public devToOwner;
mapping (address => uint) public ownerDevCount;
function _createDeveloper( string _name, uint _id, uint _age ) private{
uint id = developers.push( Developer( _name, _id, _age ) ) - 1;
ownerDevCount[msg.sender]++;
devToOwner[id] = msg.sender;
NewDeveloper(id, _name, _age);
}
function _generateRandomId( string _str ) private pure returns (uint){
uint rand = uint(keccak256(_str));
return rand;
}
function createRandomDeveloper( string _name, uint _age ) public payable {
require(_age > minAge);
require(_age < maxAge);
require(msg.value == 5000000000000000000);
uint randId = _generateRandomId( _name );
_createDeveloper(_name, randId, _age );
}
function getAllDevelopers() public view returns (uint) {
return developers.length;
}
}
如果您想更详细地了解这里发生的事情,我在第一篇和第二篇关于 Solidity 的文章中介绍过。简而言之,可以调用此合约来创建一个具有名称和年龄的 Developer 结构体。在我们的示例中,创建一个新的 Developer 需要 5 个 Ether 或 5000000000000000000 wei,这是以太坊中可能的最低面额。
接下来,进入migrations文件夹并创建一个名为2_deploy_contracts.js的文件:
const DeveloperFactory = artifacts.require('./DeveloperFactory.sol')
module.exports = function(deployer){
deployer.deploy(DeveloperFactory)
}
在这个文件中,我们导入我们的合同并将其部署到我们的区块链。
启动我们的测试环境
打开一个新的终端窗口并运行ganache-cli -p 7545
。这将在端口 7545(与我们在truffle-config.js文件中指定的端口相同)上运行 ganache-cli 并为我们创建一些帐户。每个帐户默认有 100 个以太币。你应该在控制台中看到类似这样的内容:
Available Accounts
==================
(0) 0x473c0be352f997aa0b194786c27d26e29a3f75b1
(1) 0x9657290da5570b17a03198f490b0a2d7eea84ecf
(2) 0x516c0e0152d7b85facb7e3da2d30f67e42a80ca9
(3) 0xf81be8bbe99d2302b85f7cb0f60103c435ae703b
(4) 0xcfacf5ac5567cfdd70ee5a8a9fe4bf7f74d80b02
(5) 0x623e18e34b2de07933fe179862f038230cc69012
(6) 0xd7100dbc1d6f72777ae2a6f5d95c4b8d71f7ce07
(7) 0x7f40df6c6042888a37124821130910e77051b1cf
(8) 0x26a2c2be1f31571f289b7fb60e41f31f7c57a5be
(9) 0x08a945825a28166466987d5fc77b016fe3d80aa5
当然,您的账户地址会有所不同,但您将获得 10 个账户来玩。
现在,回到你的第一个终端窗口。确保你位于为 truffle 项目创建的文件夹中,然后运行:truffle compile
,然后运行truffle migrate --network development
。这将使用以太坊虚拟机 (EVM) 可以理解的语言编译我们的代码。在这里,ganache将模拟 EVM。
如果一切顺利的话,你的终端应该显示以下内容:
truffle migrate --network development
Using network 'development'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0xc83617394674cd65f751ff9c05438e16339414ccf1e1662ba66479d79335af13
Migrations: 0xe982e78028e0dfcbdb135e7a3c1e1ed3d98e36e5
Saving successful migration to network...
... 0x78bdff98e4dac310de4650048a0856075a460bed9de0c4d4ea879ea399d142c4
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying DeveloperFactory...
... 0x0a314c5ed99c772019ea358ac98e002a1442e26903122528d705bf3ff7ed02ed
DeveloperFactory: 0xc34cc3e53850673db1dea31d267ea1738edc629f
Saving successful migration to network...
... 0x95a3cd861f067cdbe8c96f13477526eacd2a7936662f31724e1354922af49664
Saving artifacts...
请注意,在ganache-cli输出中我们的合约已经实例化:
Transaction: 0xc83617394674cd65f751ff9c05438e16339414ccf1e1662ba66479d79335af13
Contract created: 0xe982e78028e0dfcbdb135e7a3c1e1ed3d98e36e5
Gas usage: 269607
Block Number: 1
Block Time: Thu May 03 2018 21:04:55 GMT+0200 (CEST)
控制台和玩耍
现在,在运行 truffle 命令的同一个终端窗口中,运行truffle console --network development
。这将启动 truffle 控制台,并允许您与我们的区块链进行交互。我们将使用 Web3 Javascript API 来简化操作。首先,让我们取一个账户并将其放入一个变量中:
account = web3.eth.accounts[4]
接下来,我们运行以下命令:
DeveloperFactory.deployed().then(inst => {Factory = inst})
这将在 Factory 变量中分配一个合约实例。让我们确保我们的账户有 100 个以太币:
truffle(development)> web3.fromWei(web3.eth.getBalance(account).toNumber())
'100'
truffle(development)>
getBalance 方法将返回一个BigNumber类型。toNumber ()将返回账户余额(以 Wei 为单位)。我们使用fromWei()将其转换为以太币。
- 创建开发人员
好了,现在我们要调用 createRandomDeveloper 函数。如你所见,该函数接受两个参数:一个字符串类型的 _name 和一个整数类型的 _age。由于调用此函数还需要 5 个以太币,因此我们需要在函数调用中指定这一点:
truffle(development)> Factory.createRandomDeveloper('Damien', 26, {from: account, value: web3.toWei(5, "ether")})
Factory是我们的合约实例。我们为函数提供了三个参数。Damien 是 _name,26 是 _age。第三个参数是一个对象,它包含一个键from,用于识别调用它的账户,以及一个键value,用于指定该账户发送的值。这里的from值是account,也就是我们之前创建的变量。我们将 5 以太币转换为 Wei,以匹配合约中所需的值。
你的终端应该显示如下内容:
{ tx: '0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e',
receipt:
{ transactionHash: '0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e',
transactionIndex: 0,
blockHash: '0x3ef1c41cbc79d65c1282a86da3a68120a5c069709a6a5bd3e206ed85d9c270c5',
blockNumber: 5,
gasUsed: 148160,
cumulativeGasUsed: 148160,
contractAddress: null,
logs: [ [Object] ],
status: '0x01',
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000' },
logs:
[ { logIndex: 0,
transactionIndex: 0,
transactionHash: '0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e',
blockHash: '0x3ef1c41cbc79d65c1282a86da3a68120a5c069709a6a5bd3e206ed85d9c270c5',
blockNumber: 5,
address: '0x033711f6fd408b10cc94a21a3e8c20f0e75a4615',
type: 'mined',
event: 'NewDeveloper',
args: [Object] } ] }
truffle(development)>
交易成功了。这里有很多信息。我们可以看到“NewDeveloper”事件已按预期触发。我们获得了交易的哈希值、区块哈希值、使用的 Gas ……现在让我们检查一下账户余额:
truffle(development)> web3.fromWei(web3.eth.getBalance(account).toNumber())
'94.985184'
请注意,它不是 95 个以太币。这是因为当你与合约交互时,你还需要支付额外的以太币来运行交易。我们的交易信息中包含了累积 GasUsed(148160)。这意味着已经使用了 148160 Wei 来完成这笔交易。我们需要将它乘以 gasPrice。每笔交易都有一个 gasPrice。我们可以使用 transactionHash 检索它,然后将其乘以 accumulatedGasUsed 即可得到交易的以太币成本:
truffle(development)> web3.eth.getTransaction('0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e').gasPrice.toNumber() * 148160
14816000000000000
truffle(development)> web3.fromWei(14816000000000000)
'0.014816'
truffle(development)> 100 - 0.014816
99.985184
我们可以通过这种方式计算余额!我们还可以确保合约余额为 5 以太币:
truffle(development)> web3.fromWei(web3.eth.getBalance('0x033711f6fd408b10cc94a21a3e8c20f0e75a4615').toNumber())
'5'
您将在上面交易日志字段address中获取您的合约地址。最后,如果我们没有向合约发送 5 个以太币,会发生什么?让我们创建一个新帐户:
truffle(development)> account1 = web3.eth.accounts[9]
'0x5e273389dba808789a27cb792faaf31429c8de8c'
truffle(development)> web3.fromWei(web3.eth.getBalance(account1).toNumber())
'100'
现在,让我们调用 createRandomDeveloper 函数:
truffle(development)> Factory.createRandomDeveloper('Johnny', 43, {from: account1, value: web3.toWei(10, "ether")})
Error: VM Exception while processing transaction: revert
at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:41484:16)
truffle(development)> web3.fromWei(web3.eth.getBalance(account1).toNumber())
'99.9976828'
我们收到错误信息。但是,用于启动交易的 Gas 无论如何都丢失了!您可以看到账户余额不再是 100 以太币了。
结论
在下一篇文章中,我们将使用 geth 和 mist 来探索更接近真实环境的场景。希望本文能帮助你更好地理解如何开始以太坊开发。
玩得开心!
鏂囩珷鏉ユ簮锛�https://dev.to/damcosset/ethereum-development-getting-started-m09