チュートリアルのソリディティのコンパイル

ソリディティとインテリジェントイーサネットスクエア契約の開発では、アセンブラは直接対話EVMと、インテリジェントな行動契約の細かい制御を間接費のガスを減らすことができますので、それを学習し、使用するソリディティ開発者の価値があります。この記事では、コンパイルソリディティは、あなたがすぐに慣れる助けに設計されたシンプルなチュートリアルを開発する方法をソリディティスマート契約コードで埋め込みアセンブリコードへ。

スクエアイーサネットチュートリアルリンク:DAPP取得 | 電気プロバイダDAPP戦闘 | トークンの戦闘 | PHPのドッキング | Javaのドッキング | Pythonのドッキング | C#のドッキング | ダートドッキングを

2、スクエアイーサネット仮想マシンとマシンのスタック構造

スクエアEVMイーサネット仮想マシンは、独自の命令セットを持って、命令セットは、現在のオペコード144が含まれている、詳細はを参照してくださいゲスソースコード

これらの命令は、ソリディティが共同ソリディティで使用することができる抽象化されています。例えば:

contract Assembler {    
  function do_something_cpu() public {
    assembly {
      // start writing evm assembler language
    }
  }
}

圧力(PUSH)またはポップ(POP)データ:EVM仮想マシンがスタック、2つだけの操作を可能にするスタックデータ構造です。最後に、上部にあるため、LIFO(:最後に、ファーストアウトLIFO)と呼ばれる最初のポップアップ、となり、データをプッシュしています:

[画像のダンプはチェーンが失敗し、発信局は、直接アップロード(IMG-UIJDO9yW-1581813480278)(堅-組立・チュートリアル/ stack.jpg)ダウン画像を保存することが推奨され、セキュリティチェーン機構を有していてもよいです]

スタック上に保存されたVMのスタックのすべてのオペランド、仮想マシンについてのスタック詳細な情報を参照することができスタックマシンのベース

図3に示すように、機械命令コードのスタック構造

現実的な問題を解決することができるようにするために、機械の必要性のスタック構造は、ADD、SUBSTRACTなどというように、いくつかの追加の指示を、実装します。スタックのポップは、通常、スタックの結果が押し戻され、パラメータ値などの1つまたは複数の命令の実行を開始します。これは、多くの場合、逆ポーランド記法(:逆ポーランド記法RPN)と呼ばれています。

a + b      // 标准表示法Infix
a b add    // 逆波兰表示法RPN

4、ソリディティのインラインアセンブリ契約の使用

ソリディティは、で使用することができるassembly{}インラインアセンブリと呼ばれる埋め込みコンパイルされたコード:

assembly {
  // some assembly code here
}

ではassembly、コードブロックユルと呼ばれる開発言語は、簡単にするために、我々はアセンブラアセンブルまたはEVMを呼び出し、です。

もう一つの問題は、必要な場合、それは他にアクセスすることはできませんアセンブラコードブロックで定義されたブロックアセンブラ変数に、すなわち、コードブロックアセンブラ通信できないと指摘しました。例えば:

assembly { 
    let x := 2
}        
assembly {
    let y := x          // Error
}

次のように上記のコードのコンパイル時エラーが報告されます。

// DeclarationError: identifier not found
// let y := x
// ^

そして二つのパラメータを返す演算関数の結果を使用して、次のコードのインラインアセンブリコード:

function addition(uint x, uint y) public pure returns (uint) {
  assembly {
    let result := add(x, y)   // x + y
    mstore(0x0, result)       // 在内存中保存结果
    return(0x0, 32)           // 从内存中返回32字节
  }
 }

レッツは、EVM内の各命令の動作原理を説明するために、いくつかのより詳細なコメントを追加し、上記のコードを書き直します。

function addition(uint x, uint y) public pure returns (uint) { 
  assembly {        
    // 创建一个新的变量result
    //     -> 使用add操作码计算x+y
    //     -> 将计算结果赋值给变量result      
    let result := add(x, y)   // x + y   
    
    // 使用mstore操作码
    //     -> 将result变量的值存入内存
    //     -> 指定内存地址 0x0      
    mstore(0x0, result)       // 将结果存入内存
    
    // 从内存地址0x返回32字节
    return(0x0, 32)          
  }
}

5、変数定義および割り当てソリディティのコンパイル

ユルでは、使用してlet変数を定義するキーワードを。使用し:=た変数への値代入演算子:

assembly {
  let x := 2
}

いかなる場合に:=オペレータが変数に割り当てられていない場合、変数は自動的にゼロ値に初期化されます。

assembly {
  let x           // 自动初始化为 x = 0
  x := 5          // x 现在的值是5
}

あなたは、次のような変数の割り当てなどの複雑な表現を、使用することができます。

assembly {
  let x := 7 
  let y := add(x, 3)
  let z := add(keccak256(0x0, 0x20), div(slength, 32))    
  let n            
}

6、ソリディティのアセンブラ命令を聞かせて操作機構

EVMの内部では、let命令は次のタスクを実行します。

  • 新しいスタックスロットを作成します。
  • 変数のために予約スロット
  • 自己破壊のコードブロックは、スロットに達したとき

したがって、コードブロックの外に定義されたアセンブラ命令コードブロックの変数はアクセスできませんできます。

7、コメントのソリディティのコンパイル

ユルは、アセンブラで書かれており、ソリディティを使用することができる単一行のコメントとして注釈//または複数行のコメント/* */例えば:

assembly {     
  // single line comment

  /*
    Multi
    line
    comment
  */
}

8、リテラルのコンパイルソリディティ

ソリディティソリディティと一致コンパイルリテラル表現。ただし、文字列リテラルは、32文字まで含めることができます。

assembly {    
  let a := 0x123             // 16进制
  let b := 42                // 10进制
  let c := "hello world"     // 字符串

  let d := "very long string more than 32 bytes" // 超长字符串,错误!
} 

9、コンパイルおよび範囲ソリディティでブロック

ソリディティのコンパイルでは、変数のスコープは、標準的なルールに従ってください。ブレース識別のペアを使用してレンジブロック。

次の例では、YおよびZは、場合にのみブロックの範囲内で定義されています。したがって、変数yがスコープのスコープ1であり、変数zは、スコープのスコープ2です。

assembly {     
  let x := 3          // x在各处可见
    
  // Scope 1           
  {         
    let y := x     // ok    
  }  // 到此处会销毁y

  // Scope 2    
  {        
    let z := y     // Error    
  } // 到此处会销毁z
}

// DeclarationError: identifier not found
// let z := y
// ^

唯一の例外は、forループの機能と範囲で、我々は以下について説明します。

10、コンパイル内のローカル変数の関数ソリディティ

ソリディティのコンパイルでは、唯一かかわらず、変数が組み立てブロック、またはソリディティコードで定義されているかどうかの、ローカル変数にアクセスするための変数名を使用する必要がありますが、引数はローカル変数の関数である必要があります。

function assembly_local_var_access() public pure {    
  uint b = 5;    
  assembly {                // defined inside  an assembly block
      let x := add(2, 3)  
      let y := 10  
      z := add(x, y)
  }    
  assembly {               // defined outside an assembly block
      let x := add(2, 3)
      let y := mul(x, b)
  }
}

11、ソリディティのループのコンパイルの使用について

サイクルの使用でソリディティの外観。パラメータ値と関数であるN機能コードソリディティ複数n回の次の計算の変数:

function for_loop_solidity(uint n, uint value) public pure returns(uint) {         
  for ( uint i = 0; i < n; i++ ) {
    value = 2 * value;
  }    
  return value;
}

ソリディティ同等のアセンブリコードは次のとおりです。

function for_loop_assembly(uint n, uint value) public pure returns (uint) {   
  assembly {         
    for { let i := 0 } lt(i, n) { i := add(i, 1) } { 
      value := mul(2, value) 
    }  
    mstore(0x0, value)
    return(0x0, 32)
  }   
}

循環のための他の開発言語と同様に、ソリディティのコンパイルでは、forループも3つの要素が含まれています。

  • 初期化:let i := 0
  • 条件の実行:lt(i, n)あなたは関数式のスタイルでなければなりません
  • 後続の反復ステップ:add(i, 1)

注:ループの可変範囲がわずかに異なっています。変数の定義の初期化部分ではサイクルの他の部分に有効です。

12、whileループのコンパイルソリディティ

ソリディティのコンパイルでは、実際にwhileループキーワードはありませんが、同じ機能を実現するためにforループを使用することができます限り、ループ初期化と反復フォローアップのステップのための空白部分として。

assembly {
  let x := 0
  let i := 0
  for { } lt(i, 0x100) { } {     // 等价于:while(i < 0x100)
    x := add(x, mload(i))
    i := add(i, 0x20)
  }
}

if文のソリディティのコンパイルを使用して13、

ソリディティインラインアセンブラはの使用をサポートifコードの実行を設定するための条件文を、しかし、中には他の言語が存在しないelse部分が。

assembly {    
  if slt(x, 0) { x := sub(0, x) }  // Ok
  if eq(value, 0) revert(0, 0)     // Error, 需要大括号
}

コードの唯一のラインを保護する場合でも、文ブロックの中括弧が必須でなく、中括弧を使用する必要があります。これは、異なると堅実です。

あなたが条件ソリディティのインラインアセンブラの様々なチェックする必要がある場合は、使用して検討することができswitch文を。

14、ソリディティコンパイルでswitchステートメントを使用します

EVMもコンパイルされたswitch文を、それが定数複数の式の値を比較し、分岐を実行するための適切なコードを選択します。switch声明では、デフォルトのブランチをサポートしているdefault式の値は、他の分岐条件と一致しない場合、コードはデフォルトのブランチを実行します。

assembly {
  let x := 0
  switch calldataload(4)
  case 0 {
    x := calldataload(0x24)
  }
  default {
    x := calldataload(0x44)
  }
  sstore(0, div(x, 2))
}

switch声明では、いくつかの制限があります。

  • ブランチのリストは括弧を必要としないが、支店コードブロックは中括弧を必要とする - すべての分岐条件値でなければなりません:1)に同じタイプ2)の異なる値を持っている - 分岐条件がすべての可能な値をカバーするために持っている場合は、それが許可されていませんデフォルトの状態が発生します
assembly {            
  let x := 34
           
  switch lt(x, 30)
  case true {
      // do something
  }
  case false {
      // do something els
  }
  default {
      // 不允许
  }             
}

15、コンパイルソリディティで使用される機能

関数は、ソリディティのインラインアセンブラの底に定義することができます。これらの関数は、同じ呼び出しを使用し、内蔵のオペコードカスタム。

メモリを割り当てるには、次のアセンブリ機能は、長さを指定し、メモリポインタPOSを返します。

assembly {    
  function allocate(length) -> pos {
    pos := mload(0x40)
    mstore(0x40, add(pos, length))
  }    
  let free_memory_pointer := allocate(64)
}

次のように機構を操作アセンブリ機能は次のとおりです。

  • スタックからパラメータを抽出
  • 結果はスタックにプッシュされています

アセンブリコードブロックでのみ有効アセンブリ関数が定義されているので、ソリディティおよび機能は、そのようなパブリックまたはプライベートとして可視アセンブリ機能を指定する必要がありません。

16、ソリディティ演算コードのコンパイル

EVMの操作コードは、次のカテゴリに分けることができます。

  • 算術演算と比較演算
  • ビットオペレーティング
  • 暗号化操作は、現在のところ含まれていkeccak256
  • 主ブロック鎖に関連付けられた動作環境は、例えば、グローバル情報を参照し、blockhashまたはcoinbaseアカウントを受信します
  • ストレージ、メモリ、スタック操作
  • 貿易と呼び出し操作の契約
  • 停止操作
  • ログの操作

操作コードの詳細は見ることができソリディティドキュメントを


オリジナルリンク:ソリディティは、単純なチュートリアルの開発コンパイル-ワイズネット

公開された312元の記事 ウォンの賞賛159 ビュー480 000 +

おすすめ

転載: blog.csdn.net/shebao3333/article/details/104338165