assembly { qds.slot := location }
assembly { rds.slot := location }
单个智能合约具有间接用度,因此我们可以预期修建用气量将大于归并智能合约。3)路由器合约中的民众数据
CallLib合约中提供的callLib()函数与文章“编码可进级的智能合约”和OpenZeppelin的“署理转发”中提供的后备函数雷同。这是代码:
}
// Code Fragment (1) for private Router data
}
可是与上面的说明雷同,为了使出产者代码可以或许会见民众行列数据,必需在消费者合约的上下文中挪用它。
代码片断(2)、(3)和(4)凭据共享民众数据的要领。
if (success) {
出产者智能合约包括在路由合约的上下文中哄骗其本身的私有合约数据以及将项目追加到民众行列数据中的代码。
甚至:
我们将在下面的示例代码中利用这些组合的代码片断。
出产者智能合约
uint location = uint(keccak256(“router.data.location”));
default {return (0, returndatasize())}
还结构了另一个合约,该合约包罗担任的出产者和消费者条约,以利便举办天然气耗损量较量。从属合约利用沟通的分派存储要领。
该技能还要求智能合约利用民众数据举办约束,以便每个智能合约仅变动与其操纵有关的数据,而不变动共享的民众数据中的其他任何内容。
struct ProducerData {
// Code Fragments (2)(3)(4) combined
let result := delegatecall(gas(), adrs, 0,
assembly { qds.slot := location }
}
}
譬喻出产商可以是提供抵押贷款产物的银行。消费者可以是审计部分。
QueueData storage qds = queueData();
下面我们针对民众行列数据位置依次思量以下每个选项:
示例实现
}
rds.consumer = consumer;
在任何数量的Solidity智能合约和库之间共享路由器中的民众数据的要领,譬喻基于OpenZeppelin的“非布局化存储”的“ EIP-2535:钻石尺度”和“署理合约和钻石的新存储机关”中所述的钻石存储署理”和其他文献。
}
uint location = uint(keccak256(“consumer.data.location”));
为了说明该要领,我们将在选项(3)中实现简朴的Producer和Consumer模子,该模子在Router合约中的Common Data(选项(3))中举办,并着重于会见私有合约数据和共享Common行列数据的机制。
…
QueueDataLib.create(queueData(), qSize);
return router.consume();
// Code Fragment (1) for private Producer data
The Router Data – within the Router contract
// Code Fragment (1) for common queue data
}
代码片断(1)显示会见两个差异的数据布局,其私有合约数据和共享民众数据。
assembly { qds.slot := location }
既然我们已经确定了民众行列数据必需在智能合约之间共享,让我们继承举办下去。
(QueueData storage qds) {
(QueueData storage qds) {
该库包括在所有利用它的合约中。出产者合约附加项目,消费者合约删除项目,路由器合约配置行列巨细。编译器将确保最终字节码中仅提供所需的那些成果。
The Router contract
The QueueData – within the QueueData library
路由将成果挪用重定向到下级合约
rds.producer = producer;…
The Consumer Data – within the Consumer contract
共享民众数据的要领
这两个函数中也有一个能力,我们将在下面展现。
function QueueDataAt(uint location) internal pure returns
Router router;
(QueueData storage qds) {
同样在某些环境下,这大概是符合的,但在本例中不合用。
路由Produce()和Consume()函数的耗气量
…The Producer Data – within the Producer contract
在这个模子中,出产者将发生一个数据工具,当消费者筹备消费时,这个数据工具被发送给消费者举办消费。也就是说,两个智能合约必需处理惩罚沟通的数据工具,但时间差异。
这也需要一个路由合约。它与前面的选项雷同,但强制安详会见附加和删除项。 QueueData storage qds = QueueDataLocation.queueData();
// Code Fragment (4)
}
消费者合约
该代码有效地为每个民众数据工具选择了随机存储插槽。每个工具的插槽均牢靠。由于插槽是从2²⁵⁶的虚拟地点空间中随机选择的,因此位置斗嘴的大概性很小。我们在本文中将不作进一步思量。
该办理方案稍微巨大一点:必需同时向出产者和消费者提供对行列合约的引用,而且行列合约还需要知道其地点,以查抄是否答允会见。
行列数据和库
(bool ok, bytes memory bm) = callLib(address(rds.consumer));
pds.count++;
contract QueueDataLocation {
路由器合约的Produce()和Consumer()民众函数利用callLib()来挪用从属Producer和Consumer合约函数。路由和从属合约均利用Solidity成果签名(称为msg.sig)。这就是我们前面提到的能力。方针成果必需具有与路由协定中的民众成果沟通的名称和参数:
这需要路由合约。它为多个出产者和消费者提供了便利。它尚有助于变动(或进级)出产者和消费者智能合约。 return cds.total;
这利用QueueDataAt()得到对QUEUE_DATA_LOCATION处的民众行列数据的引用,这看似简朴的代码:
function action() public {
}
凡是也需要在此情况中保存所有凡是需要的出产者,消费者或路由数据,因为在出产者、消费者或路由器合约中分派存储数据是不行取的,因为这大概会包围其他合约中的存储数据。
假如办理方案中其他处所需要另一个行列,则需要将其安排在其他位置,这需要对keccak256函数利用差异的参数。
QueueDataLocation合约
RouterData storage rds = routerData();
典范的出产者与消费者模子
cds.total += item;// Code Fragment (1)
}
RouterData storage rds = routerData();
}
The QueueData library
function consume() public returns (uint total) {
function consume() public returns (uint) {
4. 尚有一系列其他原因
return queueDataAt(QUEUE_DATA_LOCATION);
}
contract CallLib {
uint location = uint(keccak256(“queue.data.location”));
contract Consumer is QueueDataLocation {
router.produce();
QueueData storage qds;
进一步的大概性
struct ConsumerData {
function producerData() internal pure returns
constructor() {
我们已经展示了利用一个简朴的路由器(有一些留意事项)可以很容易地做到这一点。 QueueDataLib.remove(QueueDataLocation.queueData());
// Code Fragment (2)
}
(bool success, uint item) =
…
}
uint location = uint(keccak256(“queue.data.location”));
3) Common Data within a Router contract
struct RouterData {
// Code Fragment (1) for private Router data
function callLib(address adrs) internal returns
// Code Fragments (2)(3)(4) combined for private Producer data
代码片断(2),(3)和(4)与私有合约数据的要领沟通。
在多个智能合约之间有很多大概的交互模子。在本文的示例中,我们设计了一个简朴的出产者到消费者模子,以便我们可以或许会合接头共享民众数据的主题。
}The QueueDataLocation contract
return abi.decode(bm, (uint256));
共享的民众数据是:
constructor(Producer producer, Consumer consumer, uint qSize) {
}
1. 出产者和消费者以差异的速度事情
我们可以将这些代码片断组合在一起以发生:
uint location = uint(keccak256(“produce.data.location”));
}
每当任何合约或库需要会见民众Queue数据时,城市执行示例函数action()中显示的代码:
必需为QueueDataAt()提供一个牢靠的随机位置,在这种环境下为QUEUE_DATA_LOCATION,该位置回收以下方法编码:
uint queueSize = 2;
// Code Fragment (3)
可是从上面的代码和数据位置图中可以看到,为了使Consumer代码可以或许会见民众行列数据,必需在Producer合约的上下文中挪用它。
contract Combined is Consumer, Producer {
uint constant QUEUE_DATA_LOCATION =
耗气量
上面的告诫也合用。
假如出产者想要节制哪个消费者正在消费哪个物品,,这大概很有用。它也有利于多个出产者。
这大概是大大都环境下的抱负办理方案,可是为了使本例的代码更简朴,我们将建设并丈量选项(3),即路由合约中的民众数据。
如上所述,由于在任何智能合约中分派传统存储数据是不行取的,因为它大概包围任何其他智能合约中的传统存储数据,因此任何私有智能合约数据也必需通过回收上述要领保持在路由情况中。
function action() public {
switch result
2) Common Data within a Consumer contract
}
// Code Fragment (2)(3)(4) combined for common queue data
(ConsumerData storage cds) {
uint location = uint(keccak256(“queue.data.location”));
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。