EOS开发者日志2017 07-7

原文地址:https://steemit.com/eos/@dan/eos-developer-log-stardate-201707-7
DQmPoWMGUwuR4Xe4udDfeD4RYyXdp185WgUmTkyHv9ehDh5_1680x8400.png
这周我们取得了两个重大突破:提炼了EOS的架构,定义了开发者API。具体地说,我们定义了一个编程模型,这个模型提供了并行处理能力,并且使代码更容易使用也更清晰。
更新示例合约
关注我们github的人可能已经注意到,我们开始整合一些示例合约,用这些示例合约来测试我们的架构,同时保证我们能覆盖到我们想要的用例。
今天的一个简单的货币合约大概是这样的:

 *  Transfer requires that the sender and receiver be the first two
 *  accounts notified and that the sender has provided authorization.
 */
struct Transfer {
  AccountName from;
  AccountName to;
  uint64_t    amount = 0;
  char        memo[]; /// extra bytes are treated as a memo and ignored by logic
};

struct CurrencyAccount {
   CurrencyAccount( uint64_t b = 0 ):balance(b){}

   uint64_t balance = 0;

   /** used as a hint to Db::store to tell it which table name within the current 
    *  scope to use.  Data is stored in tables under a structure like
    *
    *  scope/code/table/key->value
    *
    *  In this case the "singleton" table is designed for constant named keys that
    *  refer to a unique object type. User account balances are stored here:
    *  
    *  username/currency/singleton/account -> CurrencyAccount
    */ 
   static Name tableId() { return NAME("singleton"); }
};


void apply_currency_transfer() {
   const auto& transfer  = currentMessage<Transfer>();

   /** will call apply_currency_transfer() method in code defined by transfer.to and transfer.from */
   requireNotice( transfer.to, transfer.from );
   requireAuth( transfer.from );

   static CurrencyAccount from_account;
   static CurrencyAccount to_account;

   Db::get( transfer.from, NAME("account"), from_account );
   Db::get( transfer.to, NAME("account"), to_account );

   assert( from_account.balance >= transfer.amount, "insufficient funds" );
   from_account.balance -= transfer.amount;
   to_account.balance   += transfer.amount;

   if( from_account.balance == 0 )
      Db::remove<CurrencyAccount>( transfer.from, NAME("account") );
   else
      Db::store( transfer.from, NAME("account"), from_account ); 

   Db::store( transfer.to, NAME("account"), to_account ); 
}

这个货币合约有几个值得注意的方面:
1 它看起来像是普通的时序代码
2 但是它能并行地在两对用户间转账
这意味着什么呢?这意味着当alice给bob转账的同时,sam也可以给jill转账。这个货币合约的性能不再受限与单线程的性能。而单线程性能是当前货币合约的主要束缚。
开始交易所合约
我们也实现了一个简单的交易所合约,可以从两个不同的货币合约中存款和取款。

   uint64_t   a = 0;
   uint64_t   b = 0;
   int        open_orders = 0;

   bool isEmpty()const { return !(a|b|open_orders); }
   /**
    *  Balance records for all exchange users are stored here
    *  exchange/exchange/balance/username -> Balance
    */
   static Name tableId() { return Name("balance"); }
};



/**
 *  This method is called after the "transfer" action of code
 *  "currencya" is called and "exchange" is listed in the notifiers.
 */
void apply_currencya_transfer() {
   const auto& transfer  = currentMessage<Transfer>();

   if( transfer.to == "exchange" ) {
      static Balance to_balance;
      Db::get( transfer.from, to_balance );
      to_balance.a += transfer.amount;
      Db::store( transfer.from, to_balance );
   } else if( transfer.from == "exchange" ) {
      requireAuth( transfer.to ); /// require the reciever of funds (account owner) to authorize this transfer

      static Balance to_balance;
      auto balance = Db::get( transfer.to, to_balance );
      assert( balance.a >= transfer.amount, "insufficient funds to withdraw" );
      balance.a -= transfer.amount;

      if( balance.isEmpty() )
         Db::remove<Balance>( transfer.to );
      else
         Db::store( transfer.to, to_balance );
   } else {
      assert( false, "notified on transfer that is not relevant to this exchange" );
   }
}

/**
 *  This method is called after the "transfer" action of code
 *  "currencya" is called and "exchange" is listed in the notifiers.
 */
void apply_currencyb_transfer() {
   const auto& transfer  = currentMessage<Transfer>();

   if( transfer.to == "exchange" ) {
      static Balance to_balance;
      Db::get( transfer.from, to_balance );
      to_balance.b += transfer.amount;
      Db::store( transfer.from, to_balance );
   } else if( transfer.from == "exchange" ) {
      requireAuth( transfer.to ); /// require the reciever of funds (account owner) to authorize this transfer

      static Balance to_balance;
      auto balance = Db::get( transfer.to, to_balance );
      assert( balance.b >= transfer.amount, "insufficient funds to withdraw" );
      balance.b -= transfer.amount;

      if( balance.isEmpty() )
         Db::remove<Balance>( transfer.to );
      else
         Db::store( transfer.to, to_balance );
   } else {
      assert( false, "notified on transfer that is not relevant to this exchange" );
   }
}

这个实现中有意思的一点是,存款和取款发生后不需要异步回调,或者其他的复杂的挂起。
与其让用户叫交易所通过货币合约去提取资金,不如让交易所批准每个人都能从交易所转账,只需要加上说明:交易所处理转账既包括存款也包括取款。如果一个用户通过交易所合约提款,但是账上却不够钱,那么交易所合约处理器将会拒绝此次转账请求。
交易所合约存款和取款这一部分,我们还没怎么实现工作测试,但是这已经安排到下周的工作日程中了。我们还会实现一个基础的社交媒体应用,以此证明我们覆盖了所有存在的用例。
同步调用
本周在架构方面最大的进展就是,允许紧密相连的应用间可以同步调用,同时保留了并行处理的好处。以后会发blog对内存和并行执行架构进行详细介绍。
存储成本
有些人表达过一种担忧:如果代币市值达到300亿美金时,而存储能力却只有1TB的话,那么存储的成本将会非常高。我已经准备了一篇文章,在这篇文章中我会解释我们怎么处理这个问题,把存储的成本从代币价格上独立出来。

Eos.io 的开发取得了重大突破。