65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Azure Blockchain 的私有联盟网络 Ethereum 中创建您自己的加密货币

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2019年2月7日

CPOL

10分钟阅读

viewsIcon

12141

在 Azure 中创建自己的加密货币和私有联盟网络

引言

区块链和加密货币这两个词已经颠覆市场很长一段时间了,它们对行业产生了巨大的影响。看起来它有自己的未来,所以我写了一些关于它的内容。在这篇文章中,我们将创建自己的加密货币和我们在Azure上的私有联盟网络。我们将使用Azure的以太坊工作量证明联盟解决方案。听起来很有趣?如果是,我们就跳过介绍,直接开始。希望你会喜欢这篇文章。

背景

我们将把这篇文章分成三部分

  1. 区块链和加密货币简介
  2. 在Azure上创建您自己的私有联盟网络
  3. 创建您自己的私有加密货币

什么是区块链和加密货币?

区块链

我们可以将区块链总结为以下几点

  1. 它是一个包含记录的不断增长的区块链/列表。
  2. 这些区块通过密码学链接或链在一起。
  3. 每个区块都有自己独特的加密哈希值。
  4. 每个区块都有一个“前一个哈希”属性,这是前一个区块的哈希值。
  5. 链的第一个区块称为创世区块,只有这个区块没有“前一个哈希”属性。
  6. 哈希、前一个哈希、数据、时间戳是区块的最小内容。
  7. 这里的数据可以是任何东西,例如,它可以是交易详情,如“转账金额”、“发送方”、“接收方”等。

为什么区块链能抵抗数据篡改?

区块链在设计上就能抵抗数据篡改。为什么?区块链中的每个区块都有自己独特的加密哈希值和前一个哈希属性。假设每次数据或时间戳发生修改时,哈希值都会重新生成。所以,如果你对任何区块进行任何修改,哈希属性就会变成另一个值,下一个区块的前一个哈希属性将失效,依此类推。因此,整个网络将不得不经历更新过程,这在技术上是不可能的。

每当有更新时,就会生成一个新的区块,并通过将其前一个哈希属性设置为最后一个区块的哈希属性来将其链接到网络。

区块链

区块链可以应用的实时场景有哪些?

区块链几乎无处不在,你可以想想它的应用场景。我将分享一些可以应用它的地方。

  1. 如果我们所有的政府文件都被视为一个区块怎么办?伪造文件将成为一项不可能的任务。不是吗?
  2. 借助智能合约,我们甚至可以将区块链用于某些业务场景,需要实时验证,其中每个阶段都可以视为一个区块。

加密货币

加密货币是一种数字货币,它使用强大的加密安全,与纸币、硬币等实物货币不同,它没有实物形态。加密货币的所有交易都通过网络节点进行验证,所有内容都记录在区块链上。

世界上最著名的加密货币是比特币,它是由一位不知名人士或一群人发明的,被称为中本聪,这个人也是区块链的发明者。

我们都将钱发送和接收到我们的账户,但我们使用中间人,那就是银行。现在,如果我们移除中间人并用区块链替换它呢?这就是加密货币的地位。有了加密货币和区块链,我们就无需担心银行收取的高额交易费用和安全性。我个人认为,将来会有一个时期,将不再有实物货币。

创建您自己的加密货币

我们离创建自己的加密货币只有一步之遥了。在此之前,我们应该创建一个私有联盟网络,我们可以在其中添加区块链。有两件事您必须牢记:

  1. Token

币是一种加密货币,它使用自己的区块链,而代币是一种使用现有区块链的加密货币。例如,比特币使用自己的区块链。我们将使用现有的区块链,也就是以太坊。

让我们创建一个以太坊账户。

创建以太坊账户

要使用以太坊区块链,我们需要一个以太坊账户,在此步骤中,我们将了解如何创建一个。有很多方法可以做到这一点,其中一种是使用现有的工具 MetaMask。您可以将其视为一个钱包/银行,您可以在其中创建新账户并进行交易。您可以通过 Google Chrome 扩展程序安装 MetaMask,在那里您可以创建以太坊账户并注册到网络。要安装它,请转到Chrome网上应用店并搜索MetaMask,然后点击“添加到Chrome”。

安装扩展程序后,您将被重定向到一个欢迎页面,您也可以通过单击新的扩展程序图标手动转到该页面。继续完成所有步骤,直到出现“秘密备份短语”页面,这是您获得备份短语的地方,如果忘记密码,可以使用它来恢复您的账户。所以请复制一份。

MetaMask 账户

正如您所见,它已经为您的账户生成了一个公共加密 ID,现在可以将其视为您的账户 ID。您可以随时更改所需的网络,因为还有许多其他可用网络,但稍后我们将使用自定义选项添加我们自己的私有网络。目前,请记住将其更改为任何测试网络。

以太坊网络

创建智能合约

幸运的是,为了开发我们自己的代币,我们不需要下载任何 IDE,因为以太坊提供了自己的在线 IDE,即Remix。转到 IDE,我们将在这里开发我们自己的加密货币。这里使用的语言是 Solidity,它是一种高级面向对象编程语言,用于创建智能合约。

要创建代币,我们需要用 Solidity 编写一些代码,让我们现在就来做。复制下面的代码并粘贴到 Remix 编辑器中,我在这里将我的代币命名为 SibiCoin。您可以使用任何您想要的名称。

pragma solidity >=0.4.22 <0.6.0;

contract owned {
    address public owner;

    constructor() public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    function transferOwnership(address newOwner) onlyOwner public {
        owner = newOwner;
    }
}

interface tokenRecipient { function receiveApproval
(address _from, uint256 _value, address _token, bytes calldata _extraData) external; }

contract TokenERC20 {
    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public decimals = 18;
    // 18 decimals is the strongly suggested default, avoid changing it
    uint256 public totalSupply;

    // This creates an array with all balances
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    // This generates a public event on the blockchain that will notify clients
    event Transfer(address indexed from, address indexed to, uint256 value);
    
    // This generates a public event on the blockchain that will notify clients
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    // This notifies clients about the amount burnt
    event Burn(address indexed from, uint256 value);

    /**
     * Constrctor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     */
    constructor(
        uint256 initialSupply,
        string memory tokenName,
        string memory tokenSymbol
    ) public {
        totalSupply = 
        initialSupply * 10 ** uint256(decimals);  // Update total supply 
                                                  // with the decimal amount
        balanceOf[msg.sender] = totalSupply;      // Give the creator all initial tokens
        name = tokenName;                         // Set the name for display purposes
        symbol = tokenSymbol;                     // Set the symbol for display purposes
    }

    /**
     * Internal transfer, only can be called by this contract
     */
    function _transfer(address _from, address _to, uint _value) internal {
        // Prevent transfer to 0x0 address. Use burn() instead
        require(_to != address(0x0));
        // Check if the sender has enough
        require(balanceOf[_from] >= _value);
        // Check for overflows
        require(balanceOf[_to] + _value > balanceOf[_to]);
        // Save this for an assertion in the future
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        // Subtract from the sender
        balanceOf[_from] -= _value;
        // Add the same to the recipient
        balanceOf[_to] += _value;
        emit Transfer(_from, _to, _value);
        // Asserts are used to use static analysis to find bugs in your code. 
        // They should never fail.
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    /**
     * Transfer tokens
     *
     * Send `_value` tokens to `_to` from your account
     *
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transfer(address _to, uint256 _value) public returns (bool success) {
        _transfer(msg.sender, _to, _value);
        return true;
    }

    /**
     * Transfer tokens from other address
     *
     * Send `_value` tokens to `_to` in behalf of `_from`
     *
     * @param _from The address of the sender
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transferFrom(address _from, address _to, uint256 _value) 
     public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    /**
     * Set allowance for other address
     *
     * Allows `_spender` to spend no more than `_value` tokens in your behalf
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     */
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
     * Set allowance for other address and notify
     *
     * Allows `_spender` to spend no more than `_value` tokens in your behalf, 
     * and then ping the contract about it
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     * @param _extraData some extra information to send to the approved contract
     */
    function approveAndCall(address _spender, uint256 _value, bytes memory _extraData)
        public
        returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, address(this), _extraData);
            return true;
        }
    }

    /**
     * Destroy tokens
     *
     * Remove `_value` tokens from the system irreversibly
     *
     * @param _value the amount of money to burn
     */
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
        balanceOf[msg.sender] -= _value;            // Subtract from the sender
        totalSupply -= _value;                      // Updates totalSupply
        emit Burn(msg.sender, _value);
        return true;
    }

    /**
     * Destroy tokens from other account
     *
     * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
     *
     * @param _from the address of the sender
     * @param _value the amount of money to burn
     */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);                // Check if the targeted 
                                                            // balance is enough
        require(_value <= allowance[_from][msg.sender]);    // Check allowance
        balanceOf[_from] -= _value;                         // Subtract from the 
                                                            // targeted balance
        allowance[_from][msg.sender] -= _value;             // Subtract from the 
                                                            // sender's allowance
        totalSupply -= _value;                              // Update totalSupply
        emit Burn(_from, _value);
        return true;
    }
}

/******************************************/
/*       ADVANCED TOKEN STARTS HERE       */
/******************************************/

contract SibiCoin is owned, TokenERC20 {

    uint256 public sellPrice;
    uint256 public buyPrice;

    mapping (address => bool) public frozenAccount;

    /* This generates a public event on the blockchain that will notify clients */
    event FrozenFunds(address target, bool frozen);

    /* Initializes contract with initial supply tokens to the creator of the contract */
    constructor(
        uint256 initialSupply,
        string memory tokenName,
        string memory tokenSymbol
    ) TokenERC20(initialSupply, tokenName, tokenSymbol) public {}

    /* Internal transfer, only can be called by this contract */
    function _transfer(address _from, address _to, uint _value) internal {
        require (_to != address(0x0)); // Prevent transfer to 0x0 address. 
                  Use burn() instead
        require (balanceOf[_from] >= _value);                // Check if the 
                                                             // sender has enough
        require (balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows
        require(!frozenAccount[_from]);               // Check if sender is frozen
        require(!frozenAccount[_to]);                 // Check if recipient is frozen
        balanceOf[_from] -= _value;                   // Subtract from the sender
        balanceOf[_to] += _value;                     // Add the same to the recipient
        emit Transfer(_from, _to, _value);
    }

    /// @notice Create `mintedAmount` tokens and send it to `target`
    /// @param target Address to receive the tokens
    /// @param mintedAmount the amount of tokens it will receive
    function mintToken(address target, uint256 mintedAmount) onlyOwner public {
        balanceOf[target] += mintedAmount;
        totalSupply += mintedAmount;
        emit Transfer(address(0), address(this), mintedAmount);
        emit Transfer(address(this), target, mintedAmount);
    }

    /// @notice `freeze? Prevent | Allow` `target` from sending & receiving tokens
    /// @param target Address to be frozen
    /// @param freeze either to freeze it or not
    function freezeAccount(address target, bool freeze) onlyOwner public {
        frozenAccount[target] = freeze;
        emit FrozenFunds(target, freeze);
    }

    /// @notice Allow users to buy tokens for `newBuyPrice` 
    /// eth and sell tokens for `newSellPrice` eth
    /// @param newSellPrice Price the users can sell to the contract
    /// @param newBuyPrice Price users can buy from the contract
    function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {
        sellPrice = newSellPrice;
        buyPrice = newBuyPrice;
    }

    /// @notice Buy tokens from contract by sending ether
    function buy() payable public {
        uint amount = msg.value / buyPrice;                 // calculates the amount
        _transfer(address(this), msg.sender, amount);       // makes the transfers
    }

    /// @notice Sell `amount` tokens to contract
    /// @param amount amount of tokens to be sold
    function sell(uint256 amount) public {
        address myAddress = address(this);
        require(myAddress.balance >= amount * sellPrice);   // checks if the 
                                                 // contract has enough ether to buy
        _transfer(msg.sender, address(this), amount);       // makes the transfers
        msg.sender.transfer(amount * sellPrice);            // sends ether to the seller. 
        // It's important to do this last to avoid recursion attacks
    }
}

Solidity 程序的第一个步骤将以定义编译器开始。

pragma solidity >=0.4.22 <0.6.0;

编辑完代币代码后,您可以导航到编译选项卡并编译您的代码。您也可以选中“自动编译”选项,这样每次进行更改时都会自动编译代码。

以太坊 Remix Solidity 编译器

编译成功后,您可以转到运行选项卡。正如您所看到的,您在 MetaMask 中创建的账户已经为您填充了。

以太坊 Remix Solidity 运行

现在,是时候在网络上部署我们的币了,但是当您这样做时,您会收到“警告:资金不足”的错误。这是因为您的账户中只有 0 ETH,但别担心,我们会找到让你变富的方法。让我们现在创建自己的私有联盟网络,这样我们就可以向您的账户发送资金。您准备好致富了吗?

创建您自己的私有联盟网络

创建网络

登录您的 Azure 门户,然后搜索“以太坊工作量证明联盟”。这是微软为区块链爱好者创建的一个非常方便的解决方案。它部署了一个以太坊网络,由一组交易节点和一组挖掘节点来记录交易。所有配置可能需要 30 分钟到 1 小时。我会为此创建一个单独的资源组。

一切创建完成后,您应该能够转到资源组并看到所有已创建的资源。

Azure 资源

现在,单击类型为“公共 IP 地址”的资源,然后复制 DNS 名称并在浏览器中打开。您应该能看到如下页面。

以太坊节点状态 Azure DNS 名称

这里的节点以“tx-”开头的是交易节点,以“mn-”开头的是挖掘节点。挖掘是验证和批准正在发生的交易并将它们记录在账本或区块链上的过程。

向账户发送以太坊

由于我们的私有网络已准备就绪,我们可以将 MetaMask 账户网络从测试网络更改为我们创建的网络。单击网络,然后单击自定义 RPC,在新的网络文本框中,您可以输入我们之前生成的 DNS 名称。请记住,默认端口是 8545。

MetaMask 以太坊中的新网络

由于我们已经将 MetaMask 连接到我们自己的私有网络,现在我们可以轻松地从我们的网络将以太坊发送到这个账户。转到网络并粘贴 MetaMask 账户的公共加密密钥,然后单击提交。

向账户发送以太坊

如果一切顺利,您应该会收到“Ether sent!”消息。您还应该看到新的区块正在交易节点和挖掘节点中生成。现在我们可以检查我们的 MetaMask 账户了。我迫不及待想看到我变富了。

MetaMask 私有账户

哇!现在我觉得我有一个货币打印机。现在我们可以去创建智能合约了。

将智能合约部署到私有网络

现在我们去 Remix IDE,编译我们的智能合约并部署代币。

部署自定义加密货币

在这里,您可以看到我们的账户显示为 2000 以太币。在部署代币/币之前,您应该为 initialSupply(这是该合约可用的最大供应量)、tokenName(币的名称,在本例中为 SibiCoin)和 tokenSymbol(您的代币的符号)提供值。填写完所有信息后,您可以单击交易按钮。

将生成一个 MetaMask 弹出窗口,单击确认按钮。如果您没有看到弹出窗口,请单击 MetaMask Chrome 扩展程序按钮。

智能合约的初始部署

如果一切顺利,您应该能看到一个提示,表明交易已确认。

MetaMask 交易已确认

您还应该在“已部署的合约”部分看到已部署的合约,复制代币并将其添加到您现有的 MetaMask 中。

生成的智能合约代币

将自定义代币添加到 MetaMask 账户

要添加,请转到 MetaMask 账户详细信息并单击添加代币,然后提供代币地址。

添加到 MetaMask 的自定义代币

如果您想更改小数精度,应该在自定义 Solidity 代码中进行编辑。添加后,您应该能在您的账户中看到 50000 sc(SibiCoin)。

将自定义币从一个账户发送到另一个账户

要从我的“SibiAccount”账户发送 SibiCoins,我应该创建一个新账户,暂时称它为“SibiAccount 2”。现在让我们复制第二个账户的地址并发送一些币,是的,当然是免费的。请确保您也在第二个账户中添加了智能合约代币。

MetaMask 发送自定义加密货币

交易获批后,您将收到通知,币应该会反映在您的第二个账户中。

结论

哇!现在我们已经学习了

  • 什么是区块链?
  • 什么是加密货币?
  • 什么是以太坊和 MetaMask?
  • 如何创建我们自己的加密货币?
  • 如何使用 Azure 以太坊工作量证明区块链解决方案?
  • 什么是智能合约?
  • 如何使用 Remix 工具和部署自定义代币?
  • 如何在账户之间转移自定义加密货币?

您可以随时使用 Azure 中提供的监控工具,这部分留给您。

轮到您了。您怎么看?

非常感谢您的阅读。您认为这篇文章遗漏了什么吗?您觉得这篇文章有用吗?请不要忘记在下方留下评论,分享您的反馈。

历史

  • 2019 年 2 月 7 日:初版
在私有联盟网络以太坊 Azure 区块链中创建您自己的加密货币 - CodeProject - 代码之家
© . All rights reserved.