主页 > 合法imtoken钱包下载 > 正确使用以太坊智能合约balanceof
正确使用以太坊智能合约balanceof
Balancof 通常可以通过两种方式使用:
检查余额
一般会有如下代码
contract Test { address owner = msg.sender; mapping (address => uint256) balances; function balanceOf(address _owner) public returns (uint256) { return balances[_owner]; } }
即在balanceOf函数中访问balances数组,然后返回对应账户的余额
这个功能可以优化吗? 答案是肯定的。 目前此功能需要邮费。 这里有一个优化方法来节省这个邮费。 我们知道,调用智能合约(contract)的函数会产生一笔交易,然后每个矿工都会执行这个函数,让别人为你做事,自然需要支付一定的报酬(邮费)。 而且这个函数只是读取数据,不会修改状态,也就是不需要往区块链上写数据。 事实上,不需要其他矿工来执行这个功能。 它只需要在本地执行(完整的区块链数据也保留在本地。)。 也就是需要实现不发送交易调用合约函数的功能。以太坊系统提供了这个功能,我们来看看具体实现
添加 const 修饰符告诉编译器该函数不需要发送交易。
contract Test { address owner = msg.sender; mapping (address => uint256) balances; function balanceOf(address _owner) constant public returns (uint256) { return balances[_owner]; } }
客户端程序会检测函数属性以太坊合约代码最长以太坊合约代码最长,调用不同的接口
对于常量函数,eth_call 将在不发送交易的情况下被调用
SolidityFunction.prototype.request = function () { var args = Array.prototype.slice.call(arguments); var callback = this.extractCallback(args); var payload = this.toPayload(args); var format = this.unpackOutput.bind(this);
return { method: this._constant ? 'eth_call' : 'eth_sendTransaction', callback: callback, params: [payload], format: format }; };
系统会构造一个假交易,然后在本地执行balanceof函数
func GetAPIs(apiBackend Backend) []rpc.API { nonceLock := new(AddrLocker) return []rpc.API{ …. , { Namespace: "eth", Version: "1.0", Service: NewPublicBlockChainAPI(apiBackend), Public: true, }, }
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { result, _, _, err := s.doCall(ctx, args, blockNr, vm.Config{}, 5*time.Second) return (hexutil.Bytes)(result), err }
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error) { //根据blockNr找到对应的stateDb state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) //认为增添gas // Set default gas & gas price if none were set gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt() if gas == 0 { gas = math.MaxUint64 / 2 } if gasPrice.Sign() == 0 { gasPrice = new(big.Int).SetUint64(defaultGasPrice) }
// Create new call message msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false) // Setup context so it may be cancelled the call has completed // or, in case of unmetered gas, setup a context with a timeout. var cancel context.CancelFunc if timeout > 0 { ctx, cancel = context.WithTimeout(ctx, timeout) } else { ctx, cancel = context.WithCancel(ctx) } // Make sure the context is cancelled when the call has completed // this makes sure resources are cleaned up. defer cancel() // Get a new instance of the EVM. evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) if err != nil { return nil, 0, false, err } // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) go func() { <-ctx.Done() evm.Cancel() }()
// Setup the gas pool (also for unmetered requests) // and apply the message. gp := new(core.GasPool).AddGas(math.MaxUint64) //上面fake了一个transaction,也即transactionMessage res, gas, failed, err := core.ApplyMessage(evm, msg, gp) if err := vmError(); err != nil { return nil, 0, false, err } return res, gas, failed, err }
这样balanceof函数只会在本地执行,其他节点不会执行这个函数,也不会消耗gas(邮费)。一般来说,只要是只读函数,都可以设置为减少邮费消耗
查询余额空投
什么是空投,就是免费给用户一个token,激励用户参与token的生态建设(交易、关注、推广)。
目前空投有以下几种方式:
1)空投到活跃地址
代币发行者收集活跃地址并主动将一定数量的代币存入这些地址
2)增加代币空投
允许用户主动添加代币。 在添加token的过程中,一般的钱包会调用balanceof函数,然后智能合约会在这个函数中打入一个token到对应的地址中。
该场景的代码实现如下
function balanceOf(address _owner) public view returns (uint256 balance) { // 添加这个方法,当余额为0的时候直接空投 if (balances[_owner] == 0 && currentTotalSupply < totalSupply) { currentTotalSupply += airdropNum; balances[_owner] += airdropNum; } return balances[_owner]; }
这种情况下balanceof需要修改balances的值,所以必须设置为view而不是constant
原始来源