北京大学のコース学習ノート「ブロックチェーン技術と応用」シリーズのシャオ・ジェン教師 [21] イーサリアム-スマート コントラクト-1

目次

1. スマートコントラクトとは

2. スマートコントラクトのコード構造

        1. ソリッド言語

        2.入札機能

        3.フォールバック()関数

 2. 外部アカウントからスマートコントラクトを呼び出す方法

3. コントラクトが別のコントラクトの関数を呼び出す方法

        1. 直接通話

        2. アドレス型の call() 関数を使用する

        3. プロキシは delegatecall() を呼び出します。

        スマートコントラクトはイーサリアムの本質であり、イーサリアムとビットコインの最大の違いです。

1. スマートコントラクトとは

1. スマート コントラクトの本質はブロックチェーン上で実行されるコードであり、コードのロジックがスマート コントラクトの内容を定義します。
2. スマートコントラクトのアカウントは、コントラクトの現在の実行ステータスを保存します
(1) バランス: 現在の残高;
(2) nonce: トランザクション数;
(3) コード: 契約コード;
(4) ストレージ: ストレージ、データ構造は 1 つの MPT;
3. Solidity はスマート コントラクトに最も一般的に使用される言語であり、その構文は JavaScript に非常に似ています。

2. スマートコントラクトのコード構造

pragma solidity ^0.4.21;
contract SimpleAuction {
    address public beneficiary;//拍卖受益人
    uint public  auctionEnd;//结束时间
    address public highestBidder;//当前的最高出价人
    mapping( address => uint) bids;//所有竞拍者的出价
    address[] bidders;//所有竞拍者

    //需要记录的事件
    event HighestBidIncreased(address bidder,uint amount);
    event -Pay2Beneficiary( address - winner , uint amount);

    //以受益者地址 `_beneficiary` 的名义,
    //创建一个简单的拍卖,拍卖时间为 `_biddingTime` 秒。
    constructor(uint _biddingTime,address _beneficiary
        )public {
        beneficiary = _beneficiary;
        auctionEnd = now + biddingTime;
    }

    //对拍卖进行出价,随交易一起发送的ether与之前已经发送的ether的和为本次出价。
    function bid() public payable {…
    }

    //使用withdraw模式
    //由投标者自己取回出价,返回是否成功
    function withdraw() public returns (bool) {…
    }

    //结束拍卖,把最高的出价发送给受益人
    function pay2Beneficiary() public returns (bool) {…
    }
}

1.ソリッド言語

        Solidityはオブジェクト指向プログラミング言語であり、ここでのコントラクトは、多くの状態変数を定義する C++ のクラスに似ています。Solidity は厳密に型指定された言語であり、そのほとんどは、unsigned int (符号なし整数) である uint などの一般的なプログラミング言語 (C++ など) に似ています。アドレス タイプは Solidity 言語に固有です。

        上記のコードセグメントのイベントeventは、ログを記録するために使用されます。最初のイベントは HighestBidIncreased、オークションの最高入札額が増加しました、コードはオンライン オークションの例です、最新の高価格パラメーター (入札者アドレス) を記録します、金額は amount、2 番目のイベントは Pay2Beneficiary、パラメーターはオークションに勝つには、その人の住所と最後の入札金額。

        他の一般的なプログラミング言語と比較して、Solidity 言語にはいくつかの特別な機能があります。例:マッピング、マッピングはアドレスからユニットへのマッピングを保存するハッシュ テーブルです。Solidity 言語のハッシュ テーブルはトラバーサルをサポートしていません。ハッシュ テーブル内のすべての要素をトラバースしたい場合は、ハッシュ テーブル内のどの要素を記録する方法を見つけ、ビッダー配列を使用してそれらを記録する必要があります。Solidity 言語の配列は固定長にすることも、動的に長さを変更することもできます。上記のコードは、長さが動的に変化する配列です。配列に要素を追加したい場合は、プッシュ操作、つまり、bidders.push(bidder) を使用します。配列の最後に新しいビッダーを追加します。その方法を知りたいです。この配列には多くの要素が含まれているため、bidders.length を使用できます。固定長配列の場合は、address[1024] など、配列の長さを指定する必要があります。これは長さ 1024 の配列です。

        Solidity 言語でコンストラクターを定義するには 2 つの方法があり、コンストラクターは 1 つだけです1 つの方法は、C++ コンストラクターのようなコントラクトと同じ名前の関数を定義することです。この関数はパラメーターを持つことができますが、値を返すことはできません。実際、Solidity 言語の新しいバージョンでは、ここで使用する方法を推奨しています。つまり、コンストラクターを使用してコンストラクターを定義します。このコンストラクターは、コントラクトの作成時に 1 回だけ呼び出されます。

        最後に、3 つのメンバー関数があり、3 つの関数はすべてパブリックであり、他のアカウントがこれらの関数、入札関数(ここでは Payable でマークされています) を呼び出すことができることを示します。これが何を意味するかは後で説明します。

写真1-1

2.入札機能

入札関数        にはPayable があります (他の 2 つの関数にはありません)。イーサリアムでは、契約アカウントが外部送金を受け取ることができる場合、Payable としてマークする必要があると規定しています。この例での入札関数は何を意味しますか? ネットオークションの契約となり、入札機能を利用して入札を行います。たとえば、オークションに参加したい場合は、100 ETH をオファーしたいと述べてから、コントラクト内の入札関数を呼び出します。そのため、オークションのルールでは、入札関数を呼び出すときに、100 ETH のオークション入札も送信する必要があります。 100ETHをこの中に保管すると契約上、オークション終了までロックされます。何もないところから入札する人、たとえば 10,000 イーサを入札するのは避けてください。実際、あなたはそれほどお金を持っていないので、オークションに参加したいときは、送信する価格を契約に入れてロックする必要があります。そのため、入札機能は外部送金を受け取ることができるため、買掛金がマークされます。引き出し機能には支払いはありません。引き出しはオークションが終了することを意味します。最も高い入札をした人がオークションを勝ち取ります。他の人が欲しいものを手に入れられなかった場合は、引き出しを呼び出して、スマート コントラクトの元の入札価格を固定することができます。その中のイーサを取り戻します。これの目的は実際の転送ではなく、お金をスマートコントラクトに転送することではなく、単に引き出し関数を呼び出して、スマートコントラクトにロックされているお金の一部を取り戻すだけです。必要ありません。図 2-1 のトランザクションは支払い対象ではありません。

3.フォールバック()関数

function()public [payable]{
……
}

        この関数はパラメータも戻り値もなく、関数名も持たない匿名関数であり、関数名にキーワード fallback は現れません。このコントラクトを呼び出すとき、A はコントラクト B を呼び出します。その後、転送トランザクションのデータ フィールドで、B のどの関数を呼び出しているかを示す必要があります。A が契約 B に金額を送金するが、呼び出す関数が指定されておらず、データ フィールドが空の場合、この fallback() 関数がこの時点で呼び出され、他に調整する関数はありません。それ。もう 1 つの状況は、呼び出される関数が存在しないことです。データ フィールドでは、この関数を呼び出したいと言っていますが、コントラクトにはそのような関数、つまり fallback() 関数を呼び出す関数がありません。そのためです。この関数にはパラメータがありません。パラメータを指定できないため、戻り値はありません。

        fallback() 関数の場合、payable キーワードをマークすることも必要な場合があります。fallback() 関数に転送を受信する機能が必要な場合は、payable として記述する必要があります。一般的に、payable として記述されます。契約アカウントが支払い可能としてマークされた関数 (fallback() 関数を含む) が支払い可能としてマークされていない場合、この契約は外部送金を受け入れることができませんつまり、コントラクトに fallback() 関数がないか、fallback() 関数はあっても Payable が記述されていない場合、他の人がこのコントラクトに金額を送金しても、他には何も言われず、例外が発生します。データフィールドが空の場合にスローされます。

        fallback() 関数と payable は両方とも契約の定義時に記述されます。あなたに送金するときに payable や fallback() を書く必要はありません。送金するときに他に何も書かなければ、何も書きません。関数を呼び出さないと、fallback() 関数が自動的に呼び出されます。

        fallback() 関数を定義する必要はありません。コントラクトには fallback() 関数が存在しない場合があります。fallback() 関数がない場合、上記の状況が発生した場合に例外がスローされます。たとえば、呼び出す関数を指定せずにコントラクトに送金し、コントラクトで fallback() 関数が定義されていない場合、送金は間違っており、エラー処理が発生します。また、これらは契約アカウントのみにあり、外部アカウントには関係がなく、外部アカウントにはコードがありません。

        また、送金額が0でもガス料金は支払われますが、これは2つの別物です、送金金額は受取人のもの、ガス料金はブロックを解放したマイナーのものです。トランザクションはパッケージ化され、ブロックチェーンに公開されます。

 2. 外部アカウントからスマートコントラクトを呼び出す方法

        スマート コントラクトの呼び出しは、実際には送金と似ていますA が B へのトランザクション転送を開始した場合、B が普通口座であれば、これは通常の転送トランザクションであり、ビットコインの転送トランザクションと同じです。B がコントラクト アカウントの場合、この転送は実際に B のコントラクトへの呼び出しを開始し、図 2-1 に示すように、コントラクト内のどの関数が具体的に呼び出されるのかがデータ フィールドのデータ フィールドに記述されます。

図 2-1

3. コントラクトが別のコントラクトの関数を呼び出す方法

1. 直接通話

contract A {
    event LogCallFoo(string str);
    function foo(string str) returns (uint){
        emit LogCallFoo( str) ;
        return 123;
    }
}

contract B {
    uint ua;
    function cal1AFooDirectly(address addr) public{
        Aa = A(addr) ;
        ua = a.foo("call foo directly");
    }
}

        A と B の 2 つのコントラクトがあり、A のコントラクトはログとして書き込まれます。イベントはイベント LogCallFoo を定義し、LogCallFoo() を発行します。発行操作を使用してこのイベントを呼び出します。この関数は、ログを書き込むことです。プログラムの実行ロジックに影響を与えます。B コントラクトでは、関数パラメーターはアドレス (A コントラクトのアドレス) であり、このアドレスを A コントラクトのインスタンスに変換し、その中で foo 関数を呼び出します。

        イーサリアムでは、トランザクションは外部アカウントによってのみ開始できると規定されており、契約アカウントは自らの意思でトランザクションを開始することはできません。この例では、外部アカウントはコントラクト B の callAFooDirectly 関数を呼び出す必要があり、この関数はコントラクト A の foo 関数を呼び出します。

図 3-1

 2. アドレス型の call() 関数を使用する

contract c {
    function callAFooByCall(address addr) public returns (bool){
        bytes4 funcsig = bytes4(keccak256("foo(string)"));
        if ( addr.call(funcsig,"call foo by func call"))
            return true;
        return false;
    }
}

        funcsing: 呼び出される関数のシグネチャと、その後に続く呼び出しのパラメータ。このメソッドと直接呼び出しメソッドの違いはエラー処理の違いであり、直接呼び出しメソッドの実行中に呼び出されたコントラクトにエラーが発生した場合、呼び出し元のコントラクトも一緒にロールバックされます。 A のコントラクトでも例外が発生し、B のコントラクトでもエラーが発生します。address.call()の形式では、呼び出されたコントラクトが呼び出し中に例外をスローした場合、呼び出し関数は false を返し、呼び出しが失敗したことを示しますが、呼び出し元の関数は例外をスローせず、実行を続行できます。

図 3-2

3. プロキシは delegatecall() を呼び出します。

基本的にはaddress.call()メソッド        と同じです。主な違いは、delegatecall は呼び出されたコントラクトの環境に切り替えて実行する必要がなく、現在のコントラクト環境で実行できることです。当座預金口座残高ストレージなど(図 3-3 に示す)。

図 3-3


 

おすすめ

転載: blog.csdn.net/YSL_Lsy_/article/details/126544758