【问题标题】:Interfaces and contracts in ethereum以太坊中的接口和合约
【发布时间】:2017-12-20 22:03:09
【问题描述】:

我之前看到过这个问题,但我仍然需要澄清一下接口中声明的函数在哪里完全定义?我了解该界面列出并解释了另一个合约(contractB)可以使用的功能,但是该界面只是一种方便,而不是contractB使用这些功能的必要条件吗?在我看来,我将 delegateCall 与接口混淆了。如果我们想调用其他合约的函数,为什么要使用接口而不是delegateCall?如果接口指向的合约地址已经定义了函数但我没有在接口中列出,那我在contractB中还能使用吗?

例如,下面我知道我可以在众筹中使用转移功能,但转移在哪里?假设合约 A 定义了函数 makepovertyhistory() 但我没有在接口令牌中提及它......我仍然可以在众筹合约中使用它吗?

如果我在接口内重新定义了转账函数,它是否会覆盖在众售合约中实例化的地址处定义的转账函数?我不确定我是否正确地考虑了这一切,所以我想我会问更详细的问题,以防其他人发现通用答案仍然适用于一般情况,以了解正在发生的事情。

区分为什么我们会使用接口而不是将合同直接继承到我当前正在创建的合同中可能会有所帮助

interface token {
    function transfer(address receiver, uint amount);
}

contract Crowdsale {
    address public beneficiary;
    uint public fundingGoal;
....
....
..

【问题讨论】:

    标签: interface token ethereum smartcontracts


    【解决方案1】:

    Solidity 中的接口实际上与任何 OOP 中的接口没有什么不同。它们允许您在不知道底层实现的情况下编写存根代码。如果需要实现该接口的合约的新版本,则使用它的合约无需更改。

    这使您可以解决智能合约中的常见问题之一:可升级合约。通过使用接口,您可以部署新版本的合约,然后使用新地址更新任何现有合约。

    简化示例(显然,这不会通过基本的安全检查,但你明白了)。

    interface I {
      someMethod();
    }
    
    contract C {
      I i;
    
      C(address _addr) {
        i = I(_addr);
      }
    
      doSomething() {
        i.someMethod();
      }
    
      upgrade(address _newAddr) {
        i = _newAddr;
      }
    }
    

    提供这种类型的分离(并使用库)使得升级合约更容易、更便宜。

    例如,下面我知道我可以在众筹中使用转移函数,但是 转移在哪里?假设合同 A 具有功能 makepovertyhistory() 已定义但我没有在界面中提及 代币...我还能在众筹合约中使用它吗?

    不,它需要在某个地方导入或定义。

    如果我在接口内部重新定义传递函数,是吗? 覆盖在实例化地址处定义的传递函数 在众售合同范围内?

    这取决于您调用传输函数的方式。如果您在已部署合约的地址上执行它,那么您正在使用该已部署合约的实现。

    可以在this blog post 中找到更深入的示例。

    【讨论】:

    • 感谢您的回答。要真正切中要害, someMethod() 是在哪里定义的?它会在使用该接口的合约的特定地址上正确吗?所以合约 A is I{someMethod()} 部署在地址 0x1111,合约 B is I{someMethod()}部署在地址 0x2222。在 C i=I(0x2222) i.someMethod() 使用合约 B 的 someMethod 定义?因此,接口实际上并没有做任何事情,它们只是帮助将使用相同函数名称/签名的合约分组和链接在一起,即使每个合约可能对它们进行不同的定义。
    • 没错。它是必需的,以便进行调用的合约可以编译。为了让事情变得更有趣,假设你在接口 I 中定义了 2 个方法(someMethod1someMethod2),但调用合约只对调用someMethod2 感兴趣,你可以编写本地版本的接口只已定义 someMethod2()。您发布的示例显示了这一点,因为令牌接口仅定义 ERC20 规范的子集(这是示例的来源)。更有可能的情况是界面发布在某处,然后您将其导入。
    • 另外,被调用的合约甚至不需要声明为实现接口。但是,这将是非常糟糕的设计。
    • 好的,所以当我部署合约 A 时,我可以只执行合约 A{} 而不是合约 A 是 I{}?当我在新部署的合约中定义接口时,它仍然可以在合约 A 中找到函数,因为我给出了它在区块链上的地址?不声明大型接口会节省气体,因此我可以看到不定义它们的动机。这是正确的吗?我想我已经掌握了这一点,但现在我想知道为什么在 C 的合同 A 上使用 delegateCall() 不会更好,因为 delegateCall 每次调用都使用 gas,但接口调用也是如此?除了接口也需要定义所以+gas
    • 不,单独使用接口不会增加gas。您可能会将接口与库混淆。库是单例的,允许你的合约在合约的上下文中使用它们。对库的调用使用 delegatecall(),这通常更便宜,但也会带来安全风险。对于基本合约到合约调用,您可以控制调用的执行方式。您可以调用 _address.call()、_address.callcode() 或 _address.delegatecall()。但是,您是对的,通常在地址上调用 delegatecall() 会比通过接口调用方法便宜。
    猜你喜欢
    • 2016-02-28
    • 2019-04-07
    • 2018-03-15
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 1970-01-01
    • 2022-11-01
    • 2017-07-20
    相关资源
    最近更新 更多