以太坊开发:入门

2025-06-08

以太坊开发:入门

介绍

在我之前的两篇文章中,我探讨了 Solidity 语言。该语言旨在与以太坊虚拟机 (EVM) 配合使用。在本文中,我们将先讲解语言理论,然后使用一个测试环境来测试我们的合约。通过这种方式,我们将能够更好地理解以太坊的工作原理。

工具

在第一篇文章中,我们将使用truffleganache-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: '*'
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

对于 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;
    }
}

Enter fullscreen mode Exit fullscreen mode

如果您想更详细地了解这里发生的事情,我在第一篇第二篇关于 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)
}
Enter fullscreen mode Exit fullscreen mode

在这个文件中,我们导入我们的合同并将其部署到我们的区块链。

启动我们的测试环境

打开一个新的终端窗口并运行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

Enter fullscreen mode Exit fullscreen mode

当然,您的账户地址会有所不同,但您将获得 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...
Enter fullscreen mode Exit fullscreen mode

请注意,在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)
Enter fullscreen mode Exit fullscreen mode

控制台和玩耍

现在,在运行 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)>
Enter fullscreen mode Exit fullscreen mode

getBalance 方法将返回一个BigNumber类型。toNumber ()将返回账户余额(以 Wei 为单位)。我们使用fromWei()将其转换为以太币。

  • 创建开发人员

好了,现在我们要调用 createRandomDeveloper 函数。如你所见,该函数接受两个参数:一个字符串类型的 _name 和一个整数类型的 _age。由于调用此函数还需要 5 个以太币,因此我们需要在函数调用中指定这一点:

truffle(development)> Factory.createRandomDeveloper('Damien', 26, {from: account, value: web3.toWei(5, "ether")})
Enter fullscreen mode Exit fullscreen mode

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)>
Enter fullscreen mode Exit fullscreen mode

交易成功了。这里有很多信息。我们可以看到“NewDeveloper”事件已按预期触发。我们获得了交易的哈希值、区块哈希值、使用的 Gas ……现在让我们检查一下账户余额:

truffle(development)> web3.fromWei(web3.eth.getBalance(account).toNumber())
'94.985184'
Enter fullscreen mode Exit fullscreen mode

请注意,它不是 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
Enter fullscreen mode Exit fullscreen mode

我们可以通过这种方式计算余额!我们还可以确保合约余额为 5 以太币:

truffle(development)> web3.fromWei(web3.eth.getBalance('0x033711f6fd408b10cc94a21a3e8c20f0e75a4615').toNumber())
'5'
Enter fullscreen mode Exit fullscreen mode

您将在上面交易日志字段address中获取您的合约地址。最后,如果我们没有向合约发送 5 个以太币,会发生什么?让我们创建一个新帐户:

truffle(development)> account1 = web3.eth.accounts[9]
'0x5e273389dba808789a27cb792faaf31429c8de8c'
truffle(development)> web3.fromWei(web3.eth.getBalance(account1).toNumber())
'100'
Enter fullscreen mode Exit fullscreen mode

现在,让我们调用 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'
Enter fullscreen mode Exit fullscreen mode

我们收到错误信息。但是,用于启动交易的 Gas 无论如何都丢失了!您可以看到账户余额不再是 100 以太币了。

结论

在下一篇文章中,我们将使用 geth 和 mist 来探索更接近真实环境的场景。希望本文能帮助你更好地理解如何开始以太坊开发。

玩得开心!

鏂囩珷鏉ユ簮锛�https://dev.to/damcosset/ethereum-development-getting-started-m09
PREV
我保证不会再回电
NEXT
不要忘记你来自哪里...