1. 程式人生 > >10.13以太坊Solidity智慧合約彙編整合開發2和web3.eth.subscribe詳解

10.13以太坊Solidity智慧合約彙編整合開發2和web3.eth.subscribe詳解

                                                 --1--

一、獨立組裝

上面描述為內聯彙編的組合語言也可以單獨使用,實際上,計劃是將它用作Solidity編譯器的中間語言。在這種形式下,它試圖實現幾個目標:

  1. 編寫的程式應該是可讀的,即使程式碼是由Solidity的編譯器生成的。
  2. 從彙編到位元組碼的轉換應包含儘可能少的“驚喜”。
  3. 控制流應易於檢測,以幫助進行形式驗證和優化。

為了實現第一個和最後一個目標,裝配提供了高層次的結構,如for迴圈,if和switch語句和函式呼叫。它應該能夠編寫彙編程式不使用明確的SWAP,DUP, JUMP和JUMPI語句,因為前兩個模糊的資料流和最後兩個模糊處理的控制流。此外,表單的函式語句優於純操作碼語句, 因為在第一種形式中,更容易看出哪個運算元用於哪個操作碼。mul(add(x, y), 7)7 y x add mul

第二個目標是通過以非常規則的方式將更高級別的構造編譯為位元組碼來實現的。彙編程式執行的唯一非本地操作是使用者定義識別符號(函式,變數,…)的名稱查詢,它遵循非常簡單和常規的作用域規則以及從堆疊中清除區域性變數。

範圍:宣告的識別符號(標籤,變數,函式,彙編)僅在宣告它的塊中可見(包括當前塊內的巢狀塊)。跨越函式邊界訪問區域性變數是不合法的,即使它們在範圍內也是如此。不允許隱藏。在宣告區域性變數之前無法訪問它們,但函式和程式集可以。程式集是特殊塊,用於返回執行時程式碼或建立合約。在子裝配中看不到外部裝配的識別符號。

如果控制流經過塊的末尾,則插入與該塊中宣告的區域性變數數匹配的彈出指令。每當引用區域性變數時,程式碼生成器需要知道其在堆疊中的當前相對位置,因此需要跟蹤當前所謂的堆疊高度。由於在塊的末尾刪除了所有區域性變數,因此塊之前和之後的堆疊高度應該相同。如果不是這種情況,則編譯失敗。

使用switch,for和功能,它應該有可能編寫複雜的程式碼,而無需使用jump或jumpi手動。這使得分析控制流程變得更加容易,從而可以改進形式驗證和優化。 此外,如果允許手動跳轉,則計算堆疊高度相當複雜。需要知道堆疊上所有區域性變數的位置,否則既不能引用區域性變數也不會自動從塊末尾的堆疊中刪除區域性變數。 例:

我們將遵循從Solidity到彙編的示例編譯。我們考慮以下Solidity程式的執行時位元組碼: pragma solidity >=0.4.16 <0.6.0;

contract C { function f(uint x) public pure returns (uint y) { y = 1; for (uint i = 0; i < x; i++) y = 2 * y; } }

將生成以下程式集: { mstore(0x40, 0x80) // 儲存“自由記憶體指標” // 函式排程器 switch div(calldataload(0), exp(2, 226)) case 0xb3de648b { let r := f(calldataload(4)) let ret := $allocate(0x20) mstore(ret, r) return(ret, 0x20) } default { revert(0, 0) } // 記憶體分配器 function $allocate(size) -> pos { pos := mload(0x40) mstore(0x40, add(pos, size)) } // 合約函式 function f(x) -> y { y := 1 for { let i := 0 } lt(i, x) { i := add(i, 1) } { y := mul(2, y) } } }

二、彙編語法 解析器的任務如下: • 將位元組流轉換為令牌流,丟棄C ++樣式的註釋(源引用存在特殊註釋,但我們不在此解釋)。 • 根據下面的語法將令牌流轉換為AST • 使用它們定義的塊(AST節點的註釋)註冊識別符號,並注意從哪個點開始,可以訪問變數。

組裝詞法分析器遵循Solidity本身定義的元件。

空格用於分隔標記,它由字元Space,Tab和Linefeed組成。註釋是常規的JavaScript / C ++註釋,其解釋方式與Whitespace相同。

語法:

AssemblyBlock = ‘{’ AssemblyItem* ‘}’ AssemblyItem = Identifier | AssemblyBlock | AssemblyExpression | AssemblyLocalDefinition | AssemblyAssignment | AssemblyStackAssignment | LabelDefinition | AssemblyIf | AssemblySwitch | AssemblyFunctionDefinition | AssemblyFor | ‘break’ | ‘continue’ | SubAssembly AssemblyExpression = AssemblyCall | Identifier | AssemblyLiteral AssemblyLiteral = NumberLiteral | StringLiteral | HexLiteral Identifier = [a-zA-Z_$] [a-zA-Z_0-9]* AssemblyCall = Identifier ‘(’ ( AssemblyExpression ( ‘,’ AssemblyExpression )* )? ‘)’ AssemblyLocalDefinition = ‘let’ IdentifierOrList ( ‘:=’ AssemblyExpression )? AssemblyAssignment = IdentifierOrList ‘:=’ AssemblyExpression IdentifierOrList = Identifier | ‘(’ IdentifierList ‘)’ IdentifierList = Identifier ( ‘,’ Identifier)* AssemblyStackAssignment = ‘=:’ Identifier LabelDefinition = Identifier ‘:’ AssemblyIf = ‘if’ AssemblyExpression AssemblyBlock AssemblySwitch = ‘switch’ AssemblyExpression AssemblyCase* ( ‘default’ AssemblyBlock )? AssemblyCase = ‘case’ AssemblyExpression AssemblyBlock AssemblyFunctionDefinition = ‘function’ Identifier ‘(’ IdentifierList? ‘)’ ( ‘->’ ‘(’ IdentifierList ‘)’ )? AssemblyBlock AssemblyFor = ‘for’ ( AssemblyBlock | AssemblyExpression ) AssemblyExpression ( AssemblyBlock | AssemblyExpression ) AssemblyBlock SubAssembly = ‘assembly’ Identifier AssemblyBlock NumberLiteral = HexNumber | DecimalNumber HexLiteral = ‘hex’ (’"’ ([0-9a-fA-F]{2})* ‘"’ | ‘’’ ([0-9a-fA-F]{2})* ‘’’) StringLiteral = ‘"’ ([^"\r\n\] | ‘\’ .)* ‘"’ HexNumber = ‘0x’ [0-9a-fA-F]+ DecimalNumber = [0-9]+

                                            --2--

web3.eth.subscribe 該web3.eth.subscribe功能允許您訂閱區塊鏈中的特定事件。

訂閱 web3.eth.subscribe(type [, options] [, callback]);

引數

  1. String - 訂閱,您要訂閱。
  2. Mixed - (可選)可選的附加引數,具體取決於訂閱型別。
  3. Function - (可選)可選回撥,將錯誤物件作為第一個引數返回,結果返回第二個引數。將為每個傳入的訂閱呼叫,並將訂閱本身作為3引數。

返回 EventEmitter - 訂閱例項 • subscription.id:訂閱ID,用於標識和取消訂閱。 • subscription.subscribe([callback]):可用於重新訂閱相同的引數。 • subscription.unsubscribe([callback]):取消訂閱訂閱並在成功時在回撥中返回TRUE。 • subscription.arguments:訂閱引數,在重新訂閱時使用。 • on(“data”)返回Object:以日誌物件作為引數觸發每個傳入日誌。 • on(“changed”)返回Object:觸發從區塊鏈中刪除的每個日誌。該日誌將具有附加屬性。“removed: true” • on(“error”)返回Object:發生訂閱錯誤時觸發。

通知返回 • Mixed - 取決於訂閱,請參閱不同的訂閱瞭解更多資訊。

示例 var subscription = web3.eth.subscribe(‘logs’, { address: ‘0x123456…’, topics: [‘0x12345…’] }, function(error, result){ if (!error) console.log(result); });

// 取消訂閱 subscription.unsubscribe(function(error, success){ if(success) console.log(‘Successfully unsubscribed!’); });

clearSubscriptions web3.eth.clearSubscriptions()

重置訂閱。

注意 這不會重置來自其他軟體包的訂閱web3-shh,因為它們使用自己的requestManager。

引數 5. Boolean:如果true它保留"syncing"訂閱。

返回 Boolean

示例 web3.eth.subscribe(‘logs’, {} ,function(){ … });

web3.eth.clearSubscriptions();

subscribe(“pendingTransactions”) web3.eth.subscribe(‘pendingTransactions’ [, callback]); 訂閱傳入的待處理事務。

引數

  1. String- “pendingTransactions”,訂閱的型別。
  2. Function - (可選)可選回撥,將錯誤物件作為第一個引數返回,結果返回第二個引數。將為每個傳入的訂閱呼叫。

返回 EventEmitter:訂閱例項作為具有以下事件的事件發射器: • "data"返回String:觸發每個傳入的掛起事務並返回事務雜湊。 • "error"返回Object:發生訂閱錯誤時觸發。

通知返回

  1. Object|Null - 如果訂閱失敗,則第一個引數是錯誤物件。
  2. String - 第二個引數是事務雜湊。

示例 var subscription = web3.eth.subscribe(‘pendingTransactions’, function(error, result){ if (!error) console.log(result); }) .on(“data”, function(transaction){ console.log(transaction); });

// 取消訂閱 subscription.unsubscribe(function(error, success){ if(success) console.log(‘Successfully unsubscribed!’); });

subscribe(“newBlockHeaders”) web3.eth.subscribe(‘newBlockHeaders’ [, callback]); 訂閱傳入的塊頭。這可以用作計時器來檢查區塊鏈的變化。

引數

  1. String- “newBlockHeaders”,訂閱的型別。
  2. Function - (可選)可選回撥,將錯誤物件作為第一個引數返回,結果返回第二個引數。將為每個傳入的訂閱呼叫。

返回

EventEmitter:訂閱例項作為具有以下事件的事件發射器: • "data"返回Object:觸發每個傳入的塊頭。 • "error"返回Object:發生訂閱錯誤時觸發。

返回的塊頭的結構如下: • number- Number:塊編號。null當它的掛起塊。 • hash32位元組 - String:塊的雜湊。null當它的掛起塊。 • parentHash32位元組 - String:父塊的雜湊值。 • nonce8位元組 - String:生成的工作證明的雜湊值。null當它的掛起塊。 • sha3Uncles32位元組 - String:塊中的uncles資料的SHA3。 • logsBloom256位元組 - String:塊的日誌的bloom過濾器。null當它的掛起塊。 • transactionsRoot32位元組 - String:塊的事務trie的根 • stateRoot32位元組 - String:塊的最終狀態trie的根。 • receiptsRoot32位元組 - String:收據的根。 • miner- String:獲得採礦獎勵的受益人的地址。 • extraData- String:該塊的“額外資料”欄位。 • gasLimit- Number:此區塊允許的最大氣體量。 • gasUsed- Number:此塊中所有事務的總使用氣體。 • timestamp- Number:整理塊時的unix時間戳。

通知返回 4. Object|Null - 如果訂閱失敗,則第一個引數是錯誤物件。 5. Object - 像上面一樣的塊頭物件。

示例 var subscription = web3.eth.subscribe(‘newBlockHeaders’, function(error, result){ if (!error) { console.log(result);

    return;
}

console.error(error);

}) .on(“data”, function(blockHeader){ console.log(blockHeader); }) .on(“error”, console.error);

//取消訂閱 subscription.unsubscribe(function(error, success){ if (success) { console.log(‘Successfully unsubscribed!’); } });

訂閱(“同步”)

web3.eth.subscribe(‘syncing’ [, callback]); 訂閱同步事件。這將在節點同步時以及完成的同步將返回時返回一個物件FALSE。

引數

  1. String- “syncing”,訂閱的型別。
  2. Function - (可選)可選回撥,將錯誤物件作為第一個引數返回,結果返回第二個引數。將為每個傳入的訂閱呼叫。

返回 EventEmitter:訂閱例項作為具有以下事件的事件發射器: • "data"returns Object:作為引數觸發每個傳入的同步物件。 • "changed"返回Object:在啟動同步時true以及在完成同步時觸發false。 • "error"返回Object:發生訂閱錯誤時觸發。 有關返回事件的結構,Object請參閱web3.eth.isSyncing返回值。

通知返回

  1. Object|Null - 如果訂閱失敗,則第一個引數是錯誤物件。
  2. Object|Boolean- 同步物件,啟動時將返回true一次或完成後將返回false一次。

示例 var subscription = web3.eth.subscribe(‘syncing’, function(error, sync){ if (!error) console.log(sync); }) .on(“data”, function(sync){ //顯示一些同步統計資料 }) .on(“changed”, function(isSyncing){ if(isSyncing) { // 停止應用操作 } else { // 重新獲得應用操作 } });

//取消訂閱 subscription.unsubscribe(function(error, success){ if(success) console.log(‘Successfully unsubscribed!’); });

訂閱(“日誌”)

web3.eth.subscribe(‘logs’, options [, callback]); 訂閱傳入日誌,按給定選項進行篩選。

引數

  1. “logs”- String,訂閱的型別。
  2. Object - 訂閱選項

• fromBlock- Number:最早的塊數。在預設情況下null。 • address- String|Array:僅從特定帳戶獲取日誌的地址或地址列表。 • topics- Array:必須各自出現在日誌條目中的值陣列。如果你想讓主題不被使用null,順序很重要,例如。您還可以為每個主題傳遞另一個數組,其中包含該主題的選項,例如[null, ‘0x00…’][null, [‘option1’, ‘option2’]] 3. callback- Function:(可選)可選回撥,返回錯誤物件作為第一個引數,結果作為秒。將為每個傳入的訂閱呼叫。

返回

EventEmitter:訂閱例項作為具有以下事件的事件發射器: • "data"返回Object:以日誌物件作為引數觸發每個傳入日誌。 • "changed"返回Object:觸發從區塊鏈中刪除的每個日誌。該日誌將具有附加屬性。“removed: true” • "error"返回Object:發生訂閱錯誤時觸發。 有關返回事件的結構,Object請參閱web3.eth.getPastEvents返回值。

通知返回

  1. Object|Null - 如果訂閱失敗,則第一個引數是錯誤物件。
  2. Object- web3.eth.getPastEvents中的日誌物件返回值。

示例 var subscription = web3.eth.subscribe(‘logs’, { address: ‘0x123456…’, topics: [‘0x12345…’] }, function(error, result){ if (!error) console.log(result); }) .on(“data”, function(log){ console.log(log); }) .on(“changed”, function(log){ });

//取消訂閱 subscription.unsubscribe(function(error, success){ if(success) console.log(‘Successfully unsubscribed!’); });

在這裡插入圖片描述