区块链技术(三十):EOS.IO交易结构 - 开发者日志,Stardate 201707.9
发布于 16 天前 作者 stvenyin 261 次浏览 来自 分享

DY1PdSiVwAAdYPk.jpg image.png 关于我webwxgetmsgimg.jpg

基础篇: https://github.com/EOSIO/Documentation/blob/master/TechnicalWhitePaper.md

  • 区块内部组成

  • 延迟时间是指一个帐户向另一个帐户发送操作并接收响应所需的时间。目标是使两个账户能够在一个块内来回交换Actions,而不必在每个Action之间等待0.5秒。为了实现这一点,EOS.IO软件将每个块分成多个周期。每个周期分为碎片,每个碎片包含一个事务列表。每笔交易都包含一组要交付的行动。这个结构可以被视为一棵树,其中顺序和平行地处理交替层。

  • 今天我想花一点时间来解释EOS.IO事务的当前结构,以便开发人员可以更好地理解并发模型。下面是一个交易的JSON表示,它将货币从萨姆转移到爱丽丝。在这种情况下,货币,山姆和爱丽丝都是账户名称; 但是,它们以不同的方式使用。

  • {

  • “refBlockNum”: “12”,

  • “refBlockPrefix”: “2792049106”,

  • “expiration”: “2015-05-15T14:29:01”,

  • “scope”: [

  • "alice",
    
  • "sam"
    
  • ],

  • “messages”: [

  • {
    
  •   "code": "currency",
    
  •   "type": "transfer",
    
  •   "recipients": [
    
  •     "sam",
    
  •     "alice"
    
  •   ],
    
  •   "authorization": [
    
  •     {
    
  •       "account": "sam",
    
  •       "permission": "active"
    
  •     }
    
  •   ],
    
  •   "data": "a34a59dcc8000000c9251a0000000000501a00000000000008454f53000000000568656c6c6f"
    
  • }
    
  • ],

  • “signatures”: []

  • }

  • 使用单个签名序列化为二进制时,此事务大小约为160个字节,略大于大约120个字节的Steem传输或大约94个字节的BitShares传输。大部分额外的大小来自于必须明确指定收件人,授权和范围,这些收件人,授权和范围共同向消息添加51个字节。

  • TaPoS - 作为股权证明的交易

  • 熟悉Steem&BitShares的人会认识到交易的前三个领域; 他们保持不变。TaPoS使用这些字段(交易作为权益证明),并确保此交易只能包含在引用块之后和到期之前。

  • 范围

  • 下一个字段“范围”对于EOS.IO来说是新的,并指定了可以读取和/或写入的数据范围。如果消息试图读取或写入范围之外的数据,则事务将失败。只要没有范围重叠,交易可以并行处理。

  • EOS.IO软件的一个关键创新是范围和代码是两个完全独立的概念。即使我们使用货币合约的代码执行转帐,您也会注意到货币合约未在范围中引用。

  • 消息

  • 一个事务可以有一个或多个消息,这些消息必须按原子顺序应用(全部成功或全部失败)。在这种情况下,只有一条消息,所以让我们仔细看看消息:

  • 码:

  • 每条消息都必须指定要执行的代码,在这种情况下,货币合约的代码将被执行,从而导致调用以下方法:

  • currency::apply_currency_transfer(data)

  • 类型:

  • 类型字段定义了消息的类型(以及隐含的数据格式)。从面向对象编程的角度来看,您可以在“货币” 类中将类型视为方法 “名称” 。在这个例子中,类型是“传输”,因此解释了被调用方法的命名:

  • ${namespace}::apply_${code}_${type}( data )

  • 如果“命名空间”是货币合同; 但是,apply_currency_transfer也可以在其他名称空间中调用同样的方法。

  • 收件人:

  • 除了调用外currency::apply_currency_transfer(data),apply_currency_transfer(data)还会为列出的每个收件人调用该方法。例如,下列方法将按此顺序依次调用:

  • currency::apply_currency_transfer(data)

  • alice::apply_currency_transfer(data)

  • sam::apply_currency_transfer(data)

  • 该符号account::指定实施该方法的合同。 如果alice和sam在执行时没有任何特殊的逻辑执行,可能会选择不执行此方法currency::apply_currency_transfer。但是,如果山姆是一个交易所,那么山姆可能会希望在进行货币转移时处理存款和提款。

  • 生成交易的人可以添加任意数量的收件人(只要他们全部执行得足够快)。此外,某些合同可能要求通知某些当事方。在货币的情况下,发送者和接收者都需要被通知。您可以看到这是如何在货币合约中指定的。

  • void apply_currency_transfer() {

  • const auto& transfer = currentMessage<Transfer>();

  • requireNotice( transfer.to, transfer.from );

  • }

  • 授权:

  • 每封邮件可能需要一个或多个帐户的授权。在Steem和BitShares中,根据消息类型隐式定义所需的授权; 但是,对于EOS.IO,消息必须明确定义所提供的授权。EOS.IO系统将自动验证交易是否已通过所有必要的签名进行签名,以授予指定的授权。

  • 在这种情况下,消息表明它必须由sam的活动许可级别签名。该货币代码将验证SAM的授权提供了依据。您可以在示例货币合约中查看该支票。

  • void apply_currency_transfer() {

  • const auto& transfer = currentMessage<Transfer>();

  • requireNotice( transfer.to, transfer.from );

  • requireAuth( transfer.from );

  • }

  • 数据:

  • 每份合同都可以定义它自己的数据格式。没有ABI,数据只能被解释为十六进制数据; 但是,货币合约将数据的格式定义为Transfer结构:

  • struct Transfer {

  • AccountName from;

  • AccountName to;

  • uint64_t amount = 0;

  • };

  • 有了这个定义,我们可以将二进制blob转换为类似于:

  • { “from” : “sam”, “to”: “alice”, “amount”: 100 }

  • 调度

  • 现在我们了解了EOS.IO事务的结构,我们可以看一下EOS.IO块的结构。每个块被分成顺序执行的循环。在每个周期内,有多个并行执行的线程。诀窍是确保没有两个线程包含交叉作用域的事务。如果单个周期内的线程之间存在任何范围重叠,则可以在不参考任何外部数据的情况下声明块。

  • 结论

  • 并行执行的最大挑战是确保同一数据不被两个线程同时访问。与传统的并行编程不同,不可能在内存访问周围使用锁,因为执行的结果必然是非确定性的,并有可能破坏共识。即使锁是可能的,它们也是不可取的,因为大量使用锁会降低性能,低于单线程执行的性能。

  • 在访问数据时锁定的替代方法是在执行计划时锁定。从这个角度来看,范围字段定义了交易希望获得锁定的账户。调度器(又名块生产者)确保没有两个线程同时尝试获取相同的锁。通过这种事务结构和调度,可以极大地缓解内存访问冲突,并增加并行执行的机会。

  • 与其他平台不同,代码(货币契约)与数据(账户存储)的分离使锁定需求分离。如果货币合同及其数据被捆绑在一起,那么每次转账都必须锁定货币合约,所有转账都将受到单线程吞吐量的限制。但是,由于转账消息只需锁定发件人和收件人的数据,因此货币合同不再是瓶颈。

  • 在考虑交换合同时,将货币合约从瓶颈中移除是非常重要的。每次存款或退出交易所时,货币合约和交易合约都被强制转入同一线程。如果这两个合同都被大量使用,那么它会降低所有货币和所有交易所用户的表现。

  • 在EOS.IO模式下,两个用户可以转移,而不用担心任何其他账户/合同的顺序(单线程)吞吐量,而不是传输中涉及的那些。

2 回复

@stvenyin 你要想分享,请注意排版,大哥,你发的一系列,真心没法让人看。

回到顶部