当前位置:网站首页>钻石标准--Diamond Standard

钻石标准--Diamond Standard

2020-11-06 20:21:55 怎当她临去时秋波那一转

 
 

钻石标准主要是为了对应以太坊上智能合约大小24K字节的限制。同时也可以应用来处理智能合约的无缝升级问题。钻石合约是这样的一个合约:它将函数调用代理调用(delegatecall)到外部已经部署的合约。这样的外部已部署合约被称为钻石面(facets)

标准

钻石标准定义在EIP2535中。标准文本在这里https://github.com/ethereum/EIPs/issues/2535

 

例子实现

下面是钻石标准的作者 Nick Mudge提供的几个标准实现
- [ diamond-1 ] ( https://github.com/mudgen/diamond-1 )
- [ diamond-2 ] ( https://github.com/mudgen/diamond-2 )
- [ diamond-3 ] ( https://github.com/mudgen/diamond-3 )

 

概览

diamondCut 函数是用来合约升级的函数,可以增加,替代和删除钻石合约里的任意函数 。它接收一个bytes[]类型的参数输入,指明修改内部映射表所需要的方法-钻石面对。比如,调用diamondCut函数可以一次性在一个交易里增加2个新函数,替换3个函数并且删除4个函数。同时diamondCut函数可以触发事件,记录所有的增加,替换和删除。

放大镜(The Loupe)是用来查询钻石合约的内部状况。钻石合约提供4个函数来提供钻石合约当前存储的函数和钻石面。这些函数被统称为放大镜。所有的钻石合约都必须实现这些函数

 

例子解释

下面我们以diamond-1为例来说明

数据结构

在IDiamondCut.sol, 有如下的数据结构:

    struct FacetCut {
        address facetAddress;   // 当前钻石面(Facet)的地址
        FacetCutAction action;  // 当前DiamondCut的操作,增删改查
        bytes4[] functionSelectors;  // 该钻石面(Facet)所支持的函数选择子的集合
    }

在IFacet.sol, 有如下的数据结构:

    struct Facet {
        address facetAddress;  // 本钻石面(Facet)地址
        bytes4[] functionSelectors;   // 本钻石面(Facet)所支持的函数选择子的集合
    }

IDiamondLoupe.sol中定义了需要实现的4个函数:

    /// @notice Gets all facet addresses and their four byte function selectors.
    /// @return facets_ Facet
    function facets() external view returns (Facet[] memory facets_);

    /// @notice Gets all the function selectors supported by a specific facet.
    /// @param _facet The facet address.
    /// @return facetFunctionSelectors_
    function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);

    /// @notice Get all the facet addresses used by a diamond.
    /// @return facetAddresses_
    function facetAddresses() external view returns (address[] memory facetAddresses_);

    /// @notice Gets the facet that supports the given selector.
    /// @dev If facet is not found return address(0).
    /// @param _functionSelector The function selector.
    /// @return facetAddress_ The facet address.
    function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);

在LibDiamond.sol中,定义了下面的数据结构

    struct FacetAddressAndSelectorPosition {
        address facetAddress;
        uint16 selectorPosition;
    }

    struct DiamondStorage {        
        // function selector => facet address and selector position in selectors array
        mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition;
        bytes4[] selectors;        
        mapping(bytes4 => bool) supportedInterfaces;
        // owner of the contract
        address contractOwner;
    }

 

包装合约

Dianmond合约是标准的入口。Diamond合约中除了一些初始化的工作以外,最主要的下面的Proxy功能。

下面的程序要点:

  • ds.slot是内联汇编,意思是获取状态变量ds的Slot(存储槽)位置。见https://solidity.readthedocs.io/en/v0.7.4/assembly.html
  • 通过调用的传递过来的函数选择子获取facet的地址
  • 通过Delegatecall汇编指令来调用相应钻石面(facet)里的函数
    fallback() external payable {
        LibDiamond.DiamondStorage storage ds;
        bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
        address facet = address(bytes20(ds.facetAddressAndSelectorPosition[msg.sig].facetAddress));
        require(facet != address(0), "Diamond: Function does not exist");
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
                case 0 {
                    revert(0, returndatasize())
                }
                default {
                    return(0, returndatasize())
                }
        }
    }

参考文献

  1. https://medium.com/1milliondevs/new-storage-layout-for-proxy-contracts-and-diamonds-98d01d0eadb
  2. https://dev.to/mudgen/understanding-diamonds-on-ethereum-1fb
  3. https://learnblockchain.cn/article/1398
  4. https://naturaldao.io/collaboration/blog-cn/113-eip-2535%E5%8D%B3%E9%92%BB%E7%9F%B3%E6%A0%87%E5%87%86%E4%BB%8B%E7%BB%8D.html
  5. https://medium.com/1milliondevs/solidity-storage-layout-for-proxy-contracts-and-diamonds-c4f009b6903
  6. https://hiddentao.com/archives/2020/05/28/upgradeable-smart-contracts-using-diamond-standard
  7. https://hiddentao.com/archives/2019/10/03/upgradeable-smart-contracts-with-eternal-storage
  8. https://hiddentao.com/archives/2020/03/19/nested-delegate-call-in-solidity
  9. https://hiddentao.com/archives/2020/05/28/upgradeable-smart-contracts-using-diamond-standard

 

版权声明
本文为[怎当她临去时秋波那一转]所创,转载请带上原文链接,感谢
https://my.oschina.net/gavinzheng731/blog/4704491