淘先锋技术网

首页 1 2 3 4 5 6 7
                                                 --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!’);
});

在这里插入图片描述