孤荷凌寒自学python第124天区块链038以太坊的 erc20代币08

【主要内容】

今天继续使用erc20标准规范按一篇网络博文的教程进行亲自敲打代码来写一个可以发行token的智能合约。今天只好另找一个功能更完备的智能合约来进行学习和部署,合约部署成功,但不知为何调用合约中的函数方法失败。学习共用时53分钟。

(此外整理作笔记花费了约64分钟)

详细学习过程见文末学习过程屏幕录像。

【学习笔记】

一、今天理解了在remix在线编译器中,sol文件的import引用要在路径中使用./这样的格式:

于是StandardToken.sol被修改为:

```

pragma solidity ^0.4.4;

 

import "./Token.sol";

 

contract StandardToken is Token{

    mapping (address => uint256) balances;

    mapping (address => mapping (address => uint256)) allowed;

    uint256 public totalSupply;

    function transfer(address _to,uint256 _value) returns (bool success){

        //此函数仅用于调用合约的节点(或者理解为创建这个合约的节点?)地址进行代币的发送到_to形参指定的节点地址。

        //可以发送的代币的数量_value这个形参的数值类型是 uint256,可以理解为只能是大于等于零的数,且最大值为2^256-1(为什么要减一呢?因为从0开始)

        //实际上这个形参的数值类型就限定了最大可以发送的代币的数量,最多只允许2^256-1。

        //下一行代码要进行发送方现有代币余额的检查,以确认可以发送这么多的代币。

        if (balances[msg.sender]>=_value && _value>0){

            //--如果发送方节点有这么多_value,那么执行代币在两个节点间的转移

            balances[msg.sender]-=_value;

            balances[_to]+=_value;

            //---触发事件----

            Transfer(msg.sender,_to,_value);

            //--返回处理结果----

            return true;

        }else{

            return false;

        }

 

    }

 

    function transferFrom(address _from,address _to,uint256 _value) returns (bool success){

        //此函数形参_from指定的节点地址进行代币的发送到_to形参指定的节点地址。(是否是在进行授权节点(合约的节点?)的代币支配转移?)

        //可以发送的代币的数量_value这个形参的数值类型是 uint256,可以理解为只能是大于等于零的数,且最大值为2^256-1(为什么要减一呢?因为从0开始)

        //实际上这个形参的数值类型就限定了最大可以发送的代币的数量,最多只允许2^256-1。

        //下一行代码要进行发送方现有代币余额的检查,以确认可以发送这么多的代币。

        //同时检查,发送方授权给授权接受方的可支配代币金额是否大于等于_value

        if (balances[_from]>=_value && allowed[_from][msg.sender]>=_value && _value>0){

            //allowed[_from][msg.sender]中:

            //_from指的是代币真正的发送方(此节点代币才真正减少),而[msg.sender]指的是_from授权的接受节点(此节点可以动用_from节点限定数量的_value)

            //为什么这儿的授权接受方是[msg.sender]没有完全理解 。

            //--如果发送方节点有这么多_value,那么执行代币在两个节点间的转移

            balances[_from]-=_value; //真正发送代币的节点的代币数量减少

            balances[_to]+=_value; //接收代币的节点代币数量增加

            allowed[_from][msg.sender]-=_value; //授权的可动用的代币数量也减少

            //上一行与后面的approve()函数中的allowed的对象多重列表的表示感觉有点混乱,不好理解,其实原因是:

            //此函数一般由之前接受过某节点(这儿指_from节点)授权的节点来调用,因此此处allowed对象表示接受授权的节点就是【msg.sender】(指当前调用合约的这个节点)

 

            //---触发事件----

            Transfer(_from,_to,_value);

            //--返回处理结果----

            return true;

        }else{

            return false;

        }

 

    }

 

    function balanceOf(address _owner) constant returns (uint256 balance){

        //此合约函数用于外部调用合约时,返回指定节点_owner目前的代币余额。

        return balances[_owner];

    }

 

    function approve(address _spender, uint256 _value) returns (bool success) {

        //此合约由调用合约的节点(msg.sender)向指定的节点_spender授权,让_spender节点可以调用发起授权的节点指定_value数量的值。

        //调用此合约的这个函数方法的节点,将通过此函数方法发起授权,因此 这儿——调用此合约的节点:msg.sender就是发起授权的一方。

        allowed[msg.sender][_spender]=_value;

        //下面显式引发事件

        //super.Approve(msg.sender,_spender,_value);

        return true;

    }

 

    function allowance(address _owner,address _spender) returns (uint256 remaining){

        //return uint256(allowed[_owner][_sender]);

        return 245;

    }

 

}

 

```

 

ghlhToken.sol现在变成:

```

pragma solidity ^0.4.4;

 

import "./StandardToken.sol";

 

contract ghlhToken is StandardToken {

 

    //下一个函数没有函数命名名称,属于特殊的函数

    //此函数的基本作用是,如果收到了没有指明任何相关信息的代币发送给此合约,就将这些代币扔回去。

    //此种函数名叫:Fallback 函数

    function (){

        throw; //这个单词的意思就是【扔】

    }

 

    //定义与自发行的币相关的一些属性

    string public name;                   //token名称: ghlhToken

    uint8 public decimals;                //小数位,此币种最小的单位,允许到小数点后第几位

    string public symbol;                 //标识,就是代币的缩写,如BTC

    string public version = 'H0.1';       //版本号

    //现在定义合约的建构函数

    function ghlhToken(

        uint256 _initialAmount,

        string _tokenName,

        uint8 _decimalUnits,

        string _tokenSymbol

    ){

        balances[msg.sender]=_initialAmount; //这意味着,部署合约的节点首先获得全部要发行的币的总量

        //balances这个状态变量,是在此合约继承的父合约中定义的。

        totalSupply=_initialAmount; //此状态变量记录下总共要发行的币的总量。

        name = _tokenName;                                   // token名称

        decimals = _decimalUnits;                            // token小数位

        symbol = _tokenSymbol;                               // token标识

    }

 

    //下面这个函数不属于erc20标准接口,同时完成授权与将要发送给服务合约的数据发送出去。

    //https://mp.weixin.qq.com/s/foM1QWvsqGTdHxHTmjczsw 此博文对此有比较详细的解释,不过仍然没有完全理解

    function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {

        allowed[msg.sender][_spender] = _value;

        Approval(msg.sender, _spender, _value); //引发事件,广播一次授权事件正在发生。

 

        //调用你想要通知的服务合约的 receiveApprovalcall 方法(是指提供服务的服务合约中的方法,不是当前(当前是一个代币合约)合约中的函数) ,在服务合约(就是接收实际要处理的,由发送方(此处批授权发起节点)发送的数据的合约方)中此函数的定义内容大致如下:

        //receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)

 

        //下一语句,先检查调用服务合约的receiveApprovalcall()方法是否成功,如果不成功,就throw;这个时候,是否意味着还是应当调用标准的approve()方法?

        if(!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { throw; }

       

        //---首先来自中文版官方文档的说明:https://solidity-cn.readthedocs.io/zh/develop/units-and-global-variables.html?highlight=%20keccak256#id3

        //sha3---

        //sha3(...) returns (bytes32):

        //等价于 keccak256。

        //keccak256---

        //keccak256(...) returns (bytes32):

        //计算 (tightly packed) arguments 的 Ethereum-SHA-3 (Keccak-256)哈希。

        //我的理解就是,将后面参数直接求出其哈希值来

        //博文:https://www.jianshu.com/p/682c75b10392 的说明如下:

        //SHA3采用Keccak算法,在很多场合下Keccak和SHA3是同义词,但在2015年8月SHA3最终完成标准化时,NIST调整了填充算法,标准的SHA3和原先的Keccak算法就有所区别了。在早期的Ethereum相关代码中,普遍使用SHA3代指Keccak256,为了避免和NIST标准的SHA3混淆,现在的代码直接使用Keccak256作为函数名。总结为一句话:Ethereum和Solidity智能合约代码中的SHA3是指Keccak256,而不是标准的NIST-SHA3,为了避免混淆,直接在合约代码中写成Keccak256是最清晰的。

        //--------------------------------------

        //bytes32---

        //没有找到bytes32作为函数的相关说明,我的初步理解是,就参数转换为bytes32类型的数据

        //bytes4---

        //我认为理解起来相当于强制转换的使用。

        //_spender.call----

        //http://www.chidaolian.com/article-6311-1

        //节点.call(要调用的目标(即节点)合约中的函数方法选择器,此选择的函数需要的多个参数)

        //根据此博文的描述,使用call调用是高风险的,因此 发现其它博文中的示例代码没有使用这种写法。

        //如:https://mp.weixin.qq.com/s/foM1QWvsqGTdHxHTmjczsw

        //中是这样来书写的:

        //TokenRecipient(_recipient).receiveApproval(msg.sender,

        //                                     _value,

        //                                     address(this),

        //                                     _extraData);

        //此处的_recipient应当指的就是授受授权与提供服务的服务合约的地址。

        //而TokenRecipient是使用interface方式定义的一个抽象合约(只能作为基类合约供其它合约继承,抽象合约中的函数定义是空的),不过Interface定义的这种抽象合约与之前 直接用contract定义的似乎不同。

        //用interface定义的这个抽象合约,就是专门用以跨合约之间进行函数方法的相互调用与交互的,

        //见博文:https://blog.csdn.net/weixin_34291004/article/details/91902209

        //我尚且没有完全理解。不过这种方法是否就比调用call的方法要更安全呢?

        //那这儿的这句代码也就相当于调用了服务合约的receiveApproval()方法,用以同时完成接受授权并接收收到的data数据并处理数据,完成提供的本次服务。

 

        //无论结果如何,本函数都返回成功标志,这合理?

        return true;

    }

 

}

 

```

这下子解决了提示找不到引用文件 的问题,然而 ,提示声明不存在 的两处地方仍然报错,于是不得已,只好放弃此合约,进而寻找其它合约代码。

二、从github上找到了一个更完备的合约代码

博文:https://blog.csdn.net/hopeztm/article/details/81515816

github源码地址:https://github.com/tianmz1987/dnc

此代码功能更复杂,但经过之前对solidity的不懈努力学习,今天愕然地发现,我居然可以轻松地读懂其中的代码内容,也许这就是自学,深入研究自力更生带来的好处吧。

我修改了源文件的一些代币命名的内容,修改后的代码如下:

```

pragma solidity ^0.4.21;

 

/**

 * openzeppelin-solidity@1.9.0/contracts/math/SafeMath.sol

 */

 

/**

 * @title SafeMath

 * @dev Math operations with safety checks that throw on error

 */

library SafeMath {

 

  /**

  * @dev Multiplies two numbers, throws on overflow.

  */

  function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {

    if (a == 0) {

      return 0;

    }

    c = a * b;

    assert(c / a == b);

    return c;

  }

 

  /**

  * @dev Integer division of two numbers, truncating the quotient.

  */

  function div(uint256 a, uint256 b) internal pure returns (uint256) {

    // assert(b > 0); // Solidity automatically throws when dividing by 0

    // uint256 c = a / b;

    // assert(a == b * c + a % b); // There is no case in which this doesn't hold

    return a / b;

  }

 

  /**

  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).

  */

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {

    assert(b <= a);

    return a - b;

  }

 

  /**

  * @dev Adds two numbers, throws on overflow.

  */

  function add(uint256 a, uint256 b) internal pure returns (uint256 c) {

    c = a + b;

    assert(c >= a);

    return c;

  }

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/ownership/Ownable.sol

 */

 

/**

 * @title Ownable

 * @dev The Ownable contract has an owner address, and provides basic authorization control

 * functions, this simplifies the implementation of "user permissions".

 */

contract Ownable {

  address public owner;

 

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

 

  /**

   * @dev The Ownable constructor sets the original `owner` of the contract to the sender

   * account.

   */

  function Ownable() public {

    owner = msg.sender;

  }

 

  /**

   * @dev Throws if called by any account other than the owner.

   */

  modifier onlyOwner() {

    require(msg.sender == owner);

    _;

  }

 

  /**

   * @dev Allows the current owner to transfer control of the contract to a newOwner.

   * @param newOwner The address to transfer ownership to.

   */

  function transferOwnership(address newOwner) public onlyOwner {

    require(newOwner != address(0));

    emit OwnershipTransferred(owner, newOwner);

    owner = newOwner;

  }

 

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/token/ERC20/ERC20Basic.sol

 */

 

/**

 * @title ERC20Basic

 * @dev Simpler version of ERC20 interface

 * @dev see https://github.com/ethereum/EIPs/issues/179

 */

contract ERC20Basic {

  function totalSupply() public view returns (uint256);

  function balanceOf(address who) public view returns (uint256);

  function transfer(address to, uint256 value) public returns (bool);

  event Transfer(address indexed from, address indexed to, uint256 value);

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/token/ERC20/ERC20.sol

 */

 

/**

 * @title ERC20 interface

 * @dev see https://github.com/ethereum/EIPs/issues/20

 */

contract ERC20 is ERC20Basic {

  function allowance(address owner, address spender) public view returns (uint256);

  function transferFrom(address from, address to, uint256 value) public returns (bool);

  function approve(address spender, uint256 value) public returns (bool);

  event Approval(address indexed owner, address indexed spender, uint256 value);

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/token/ERC20/BasicToken.sol

 */

 

/**

 * @title Basic token

 * @dev Basic version of StandardToken, with no allowances.

 */

contract BasicToken is ERC20Basic {

  using SafeMath for uint256;

 

  mapping(address => uint256) balances;

 

  uint256 totalSupply_;

 

  /**

  * @dev total number of tokens in existence

  */

  function totalSupply() public view returns (uint256) {

    return totalSupply_;

  }

 

  /**

  * @dev transfer token for a specified address

  * @param _to The address to transfer to.

  * @param _value The amount to be transferred.

  */

  function transfer(address _to, uint256 _value) public returns (bool) {

    require(_to != address(0));

    require(_value <= balances[msg.sender]);

 

    balances[msg.sender] = balances[msg.sender].sub(_value);

    balances[_to] = balances[_to].add(_value);

    emit Transfer(msg.sender, _to, _value);

    return true;

  }

 

  /**

  * @dev Gets the balance of the specified address.

  * @param _owner The address to query the the balance of.

  * @return An uint256 representing the amount owned by the passed address.

  */

  function balanceOf(address _owner) public view returns (uint256) {

    return balances[_owner];

  }

 

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/token/ERC20/StandardToken.sol

 */

 

/**

 * @title Standard ERC20 token

 *

 * @dev Implementation of the basic standard token.

 * @dev https://github.com/ethereum/EIPs/issues/20

 * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol

 */

contract StandardToken is ERC20, BasicToken {

 

  mapping (address => mapping (address => uint256)) internal allowed;

 

  /**

   * @dev Transfer tokens from one address to another

   * @param _from address The address which you want to send tokens from

   * @param _to address The address which you want to transfer to

   * @param _value uint256 the amount of tokens to be transferred

   */

  function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {

    require(_to != address(0));

    require(_value <= balances[_from]);

    require(_value <= allowed[_from][msg.sender]);

 

    balances[_from] = balances[_from].sub(_value);

    balances[_to] = balances[_to].add(_value);

    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);

    emit Transfer(_from, _to, _value);

    return true;

  }

 

  /**

   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.

   *

   * Beware that changing an allowance with this method brings the risk that someone may use both the old

   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this

   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:

   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729

   * @param _spender The address which will spend the funds.

   * @param _value The amount of tokens to be spent.

   */

  function approve(address _spender, uint256 _value) public returns (bool) {

    allowed[msg.sender][_spender] = _value;

    emit Approval(msg.sender, _spender, _value);

    return true;

  }

 

  /**

   * @dev Function to check the amount of tokens that an owner allowed to a spender.

   * @param _owner address The address which owns the funds.

   * @param _spender address The address which will spend the funds.

   * @return A uint256 specifying the amount of tokens still available for the spender.

   */

  function allowance(address _owner, address _spender) public view returns (uint256) {

    return allowed[_owner][_spender];

  }

 

  /**

   * @dev Increase the amount of tokens that an owner allowed to a spender.

   *

   * approve should be called when allowed[_spender] == 0. To increment

   * allowed value is better to use this function to avoid 2 calls (and wait until

   * the first transaction is mined)

   * From MonolithDAO Token.sol

   * @param _spender The address which will spend the funds.

   * @param _addedValue The amount of tokens to increase the allowance by.

   */

  function increaseApproval(address _spender, uint _addedValue) public returns (bool) {

    allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);

    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);

    return true;

  }

 

  /**

   * @dev Decrease the amount of tokens that an owner allowed to a spender.

   *

   * approve should be called when allowed[_spender] == 0. To decrement

   * allowed value is better to use this function to avoid 2 calls (and wait until

   * the first transaction is mined)

   * From MonolithDAO Token.sol

   * @param _spender The address which will spend the funds.

   * @param _subtractedValue The amount of tokens to decrease the allowance by.

   */

  function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {

    uint oldValue = allowed[msg.sender][_spender];

    if (_subtractedValue > oldValue) {

      allowed[msg.sender][_spender] = 0;

    } else {

      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);

    }

    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);

    return true;

  }

 

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/token/ERC20/BurnableToken.sol

 */

 

/**

 * @title Burnable Token

 * @dev Token that can be irreversibly burned (destroyed).

 */

contract BurnableToken is BasicToken {

 

  event Burn(address indexed burner, uint256 value);

 

  /**

   * @dev Burns a specific amount of tokens.

   * @param _value The amount of token to be burned.

   */

  function burn(uint256 _value) public {

    _burn(msg.sender, _value);

  }

 

  function _burn(address _who, uint256 _value) internal {

    require(_value <= balances[_who]);

    // no need to require value <= totalSupply, since that would imply the

    // sender's balance is greater than the totalSupply, which *should* be an assertion failure

 

    balances[_who] = balances[_who].sub(_value);

    totalSupply_ = totalSupply_.sub(_value);

    emit Burn(_who, _value);

    emit Transfer(_who, address(0), _value);

  }

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/token/ERC20/MintableToken.sol

 */

 

/**

 * @title Mintable token

 * @dev Simple ERC20 Token example, with mintable token creation

 * @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120

 * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol

 */

contract MintableToken is StandardToken, Ownable {

  event Mint(address indexed to, uint256 amount);

  event MintFinished();

 

  bool public mintingFinished = false;

 

  modifier canMint() {

    require(!mintingFinished);

    _;

  }

 

  /**

   * @dev Function to mint tokens

   * @param _to The address that will receive the minted tokens.

   * @param _amount The amount of tokens to mint.

   * @return A boolean that indicates if the operation was successful.

   */

  function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {

    totalSupply_ = totalSupply_.add(_amount);

    balances[_to] = balances[_to].add(_amount);

    emit Mint(_to, _amount);

    emit Transfer(address(0), _to, _amount);

    return true;

  }

 

  /**

   * @dev Function to stop minting new tokens.

   * @return True if the operation was successful.

   */

  function finishMinting() onlyOwner canMint public returns (bool) {

    mintingFinished = true;

    emit MintFinished();

    return true;

  }

}

 

/**

 * openzeppelin-solidity@1.9.0/contracts/token/ERC20/CappedToken.sol

 */

 

/**

 * @title Capped token

 * @dev Mintable token with a token cap.

 */

contract CappedToken is MintableToken {

 

  uint256 public cap;

 

  //----限制了最大能够铸币的数量-------

  //----这是此合约的建构函数

  function CappedToken(uint256 _cap) public {

    require(_cap > 0);

    cap = _cap;

  }

 

  /**

   * @dev Function to mint tokens

   * @param _to The address that will receive the minted tokens.

   * @param _amount The amount of tokens to mint.

   * @return A boolean that indicates if the operation was successful.

   */

  function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {

    require(totalSupply_.add(_amount) <= cap);

 

    return super.mint(_to, _amount);

  }

 

}

 

/**

 * ghlh Token, totalSupply 100000000000000000

 */

contract ghlhToken is BurnableToken, CappedToken(100000000000000000) {

    string public name = "ghlh Token";

    string public symbol = "GHLH";

    uint8 public decimals = 8;

 

    function burn(uint256 _value) onlyOwner public {

        super.burn(_value);

    }

}

 

```

编译与部署都轻松通过。

也成功在metamask狐狸钱包中,添加了自己自定义的代币。然而接下来的调用智能合约就继续面临失败的境遇了,不过在自学的道路中不断遭遇失败早已经使我变得麻木,内心再无半点波澜,不断尝试,思考,最终虽然仍以失败告终,不过却也还算是很有收获。

【尝试通过python调用自己的代币合约来进行铸币】

在此代币合约中,有一个只有创建(部署)此合约的节点地址才有权进行的铸币(Mint)方法 ,于是我想为自己的ETH地址,就是狐狸钱包的地址铸币,按之前写的的调用智能合约的方法 ,Py代码如下:

```

import time

from web3 import Web3, HTTPProvider

 

import contract_abi

 

contract_address="0xf31700c1b97f0ca3d5f228a67da7856568e14422"  #GHLH代币合约地址,就是我自己创建(部署)的智能合约

wallet_private_key="D8EF07D32389148E9DA6C54237BD5A39C92917D59340AA5D6064485C01E96FB2" #狐狸钱包的私钥

wallet_address="0x5227C3EF48B5A1bcF784593e46D9579D26a3b592" #狐狸钱包的公钥,就是钱包地址,是eth网络上的一个节点。

 

w3 = Web3(HTTPProvider("https://ropsten.infura.io/v3/79124269dc454e47bee73f964c971d3c")) #里面的参数字符串是在infura.io网站上申请 到的一个节点地址。

 

w3.eth.enable_unaudited_features() #确认我们知道可能会发生问题的情况。

 

contract = w3.eth.contract(address = contract_address, abi = contract_abi.abi)

#---上一行中,contract_abi.abi,表示引用了存放在contract_abi.py文件中的变量abi的列表

#---整个代码就是通过智能合约在eth网络上的地址 和对应ABI连接列表来得到指定的智能合约对象contract

 

print(w3.eth.blockNumber) #打印eth网络最后一个区块的id

 

def mintGhlhTokenToME(amount_for_ghlh):

    print(contract.functions.mint(wallet_address,amount_for_ghlh).call())

    #这儿失败的原因,怀疑是必须要设置GAS以交易方式 发送才行,而不是直接调用 。

 

mintGhlhTokenToME(100)

#print(ispass)

```

一切顺利,不过,在真正调用合约的方法Mint()时却报了长长的一串错误:

```

Traceback (most recent call last):

  File "G:w10_1pythonpython365libsite-packagesweb3contract.py", line 1372, in call_contract_function

    output_data = decode_abi(output_types, return_data)

  File "G:w10_1pythonpython365libsite-packageseth_abiabi.py", line 96, in decode_abi

    return decoder(stream)

  File "G:w10_1pythonpython365libsite-packageseth_abidecoding.py", line 118, in __call__

    return self.decode(stream)

  File "G:w10_1pythonpython365libsite-packageseth_utilsfunctional.py", line 46, in inner

    return callback(fn(*args, **kwargs))

  File "G:w10_1pythonpython365libsite-packageseth_abidecoding.py", line 164, in decode

    yield decoder(stream)

  File "G:w10_1pythonpython365libsite-packageseth_abidecoding.py", line 118, in __call__

    return self.decode(stream)

  File "G:w10_1pythonpython365libsite-packageseth_abidecoding.py", line 186, in decode

    raw_data = self.read_data_from_stream(stream)

  File "G:w10_1pythonpython365libsite-packageseth_abidecoding.py", line 296, in read_data_from_stream

    len(data),

eth_abi.exceptions.InsufficientDataBytes: Tried to read 32 bytes.  Only got 0 bytes

 

The above exception was the direct cause of the following exception:

 

Traceback (most recent call last):

  File "c:Userspw.vscodeextensionsms-python.python-2019.6.24221pythonFilesptvsd_launcher.py", line 43, in <module>

    main(ptvsdArgs)

  File "c:Userspw.vscodeextensionsms-python.python-2019.6.24221pythonFileslibpythonptvsd\__main__.py", line 434, in main

    run()

  File "c:Userspw.vscodeextensionsms-python.python-2019.6.24221pythonFileslibpythonptvsd\__main

 

````

如之前的做法,我尝试锚定web3.py文件的错误代码点,却无法锚定。

初步判断错误的核心在于,使用:

contract.functions.mint(wallet_address,amount_for_ghlh).call()

方式调用铸币方法,是否合适,因为这应当也算是一次事务(交易),这种调用 方法 ,却没有指明交易双方及gas设置等问题,因为上面的错误提示中,显示:

eth_abi.exceptions.InsufficientDataBytes: Tried to read 32 bytes.  Only got 0 bytes

【直接在remix的deploy and run transactions的界面上进行合约调试也无法铸币】

于是我转而在remix在线环境上,到deploy and run transactions界面进行直接调用铸币方法进行调试

首先是通过:add Address模式添加自己的合约地址

0xf31700c1b97f0ca3d5f228a67da7856568e14422

然后,在最下面选择合约名称再选择其中的方法 mint通过

通过这样的方式调用合约,首先出现提示:

Gas estimation failed

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?

gas required exceeds allowance or always failing transaction

强制发送交易(事务)后,果然要求指定GAS,本以为指定了gas就应当没有问题了,结果最终还是失败了,提示为:

Warning! Error encountered during contract execution [Reverted]

今天的学习到此就只好以失败收场。

恳请高手不吝指教,定将成分感激。明天继续奋战吧。

【学习后记】

虽然今天铸币没有成功,但从智能合约的代码中,却看到了此生从没深入理解过的东西——货币到底是什么?当我——一个渺小的我都可以铸币的时候,这意味着什么?

又想到facebook早些时候为什么一定要开展libra项目进行企业级的铸币,突然觉得自己是需要更广泛的学习经济学相关内容的时候了。

朋友们,对货币的本质你有什么样的看法呢?

更多的我关于自学的感悟,我将与大家在【就是要学】社群交流互动。

我建立【就是要学】社群的初衷就是将渴望与我一样追求自主独立的生活的朋友 ,特别是还有大把青春可以去试错的年轻朋友聚集到一起,在这个人以类聚的时代,我们在一起, 互相交流,坚持每天成长,欢迎来到【就是要学】社群QQ群:646854445

或访问:www.941xue.com

【关于坚持自学的例行说明】

最后例行说明下,我为什么要坚持自学。

“如果我不曾见过太阳,我本可以忍受黑暗,然而阳光已使我的荒凉,成为更新的荒凉。”

——艾米莉·狄金森

如果要问我对自己的前半生如何看待时,我想昨天和今天的答案都将完全不同。

昨天的我,生活在荒凉的满意之中,自觉怡然自得,拿着包身包月的工资,听着仁慈的命令,过着几乎一成不变的生活;时而与周遭的人儿和睦互往,时而唇舌相抵斤斤计较,演出着生活的鸡毛蒜皮,工作的吹拉弹唱;忘我,忘我,才能融入这平和无奇的乐章中,迈着细碎的步伐,原地踏步。那时的我觉得这就是悠然自得的听天由命的平凡人生,也就是我的宿命了。

可是某一天,我见到了不一样的太阳以及太阳下不一样的人生光景——那并不荒凉。

今天的我,生活在荒凉的痛苦之中,自觉渴望改变,迈着不知所措的步伐,看着流逝的年华,睁着悔恨错失一切的双眼… …

我知道我将再无法回到过去的我,只有改变才是唯一正确的方向。

一、为什么一把年纪还在学习

放弃很多去聚餐,去HI歌,去游玩,去看电影,去追剧……的时间,然后进行着这个年纪似乎已不应当再进行的学习,引来身边人们无尽的不解与鄙夷甚至可怜……

但我不想放弃终身学习的誓言。

因为——

我对我今天的生活现状并不认同!

罗伯特清崎告诉过我们,反省自己当下的生活是不是自己想要的,这难道不是最好的动力与答案?

走过了大半生,然后才发现曾经、当下所正在进行的人生并不是自己想要的,那是一种怎样的体验?

只有心中真切的感受才能回答这个问题,而任凭再丰富的语言也是无法描绘出来的。

经历半生的跋涉,却发现走得并不正确,有多少人有勇气承认自己过去的一切都是错误的呢?

而我愿意告诉过去的我:“你错了!”

那么已经历半生错误,年岁之大又压于头顶,还有希望从这架的梯子的半端重新爬下,再蹒跚着爬上另一架梯子吗?

我宁愿相信还有希望!

这便是我为什么要继续坚持终身学习下去的全部理由。

二、这个年纪还在学这些技术有意义吗

纯的技术对这把年纪其实已没有意义。

但兴趣可以超越意义。

但技术可以引来思想的变革,这才是意义。

投资自己的头脑 ,改革自己的思想,这是最保值,更长远的投资,过去我从来没有投资过,错过太多,那就从投资自己头脑开始吧。

罗伯特清崎告诉我们,真正的富有是时间的富有;真正的自由是可以决定自己愿意做什么的自由。

因为我愿意做我兴趣所在的事,所以我希望我有自由选择的那一天,虽然今天离那一天可能还是那么遥远,但我愿意相信,每天多赶几步,离希望就更近一步。

再者,虽然我可能再已无法完全完整的掌握这些技术了,但技术本身却可以启迪心的觉醒,激发灵感,那么只要多了解一点,我相信我将离那个正离我而去跑得越来越快的未来更近一点,不至于被未知的那个未来抛弃得太远。

于是我怎能放弃追逐求索的步伐?

我要坚信:感觉太迟的时候,也许还不算太迟。

感谢一直以来关注我,鼓励我的你!

若不嫌弃这一个到了高龄才长大的可笑可叹的我,请不吝赐教。

我的q号是:578652607,敬候你的指点。

【同步语音笔记】

https://www.ximalaya.com/keji/19103006/271639313

【学习过程屏幕录屏】

链接:https://pan.baidu.com/s/15b42k-idqcCd533VWAObZQ

提取码:nbow

欢迎大家添加我为好友: QQ: 578652607
原文地址:https://www.cnblogs.com/lhghroom/p/12542857.html