Wie kann ein Vertrag zu einem späteren Zeitpunkt selbst laufen?

In meiner Blockchain-Anwendung möchte ich ein Ereignis zu einem späteren Zeitpunkt auslösen, Stunden oder vielleicht sogar Tage, nachdem die Anwendung zuletzt eine Transaktion von einem Benutzer erhalten hat. Wie kann ich ein "Ereignis" erstellen, das nach Ablauf einer bestimmten Zeit ausgelöst wird?

Antworten (9)

Faule vs. eifrige Ausführung

Es gibt zwei grundlegende Möglichkeiten, einen Vertrag zu entwerfen, der zu einem späteren Zeitpunkt abgerufen werden soll: faule Bewertung oder eifrige Bewertung .

Lazy Evaluation bedeutet, dass der Vertragsstatus nur bei Bedarf aktualisiert wird. Dies ist oft sinnvoll für Verträge, die Benutzer natürlich dazu anregen, sie zu einem späteren Zeitpunkt anzurufen.

Ein Beispiel hierfür könnte ein Treuhandfondsvertrag sein, der bis zum 18. Geburtstag einer Person gesperrt bleibt. Diese Person wäre motiviert, die Verteilung dieser Gelder zu diesem Zeitpunkt durchzuführen.

Ein komplexeres Beispiel ist ein verzinslicher Vertrag. Angenommen, ich zahle 1 ETH ein und erhalte jeden Monat 1 % Zinsen, die sich verzinsen.

Dazu gibt es zwei Möglichkeiten:

  1. Der faule Weg: Wenn ich mein Geld abheben möchte, rufe ich den Vertrag auf und er berechnet mein Guthaben basierend auf dem Zinssatz, meinem letzten bekannten Guthaben und der verstrichenen Zeit.
  2. Der eifrige Weg: Ich benutze den Ethereum-Wecker oder einen ähnlichen Dienst, um die claimInterest()Funktion des Vertrags aufzurufen, die die Zinsen für diesen Monat berechnet und mein Guthaben belastet.

In diesem Fall ist Lazy Evaluation sinnvoll, da es einfach ist, den aktuellen Zustand basierend auf dem vergangenen Zustand und der verstrichenen Zeit zu berechnen.

Eifrige Bewertung ist nützlich, wenn Zustandsübergänge sind

  1. Rechnerisch teuer
    • Arbeiten mit großen Speichersets, Sortieren großer Listen usw.
  2. Nicht deterministisch
    • Verlässt sich auf Eingaben von außen, wie z. B. Aufrufe von Oraclize.it
  3. Fehlende Anreize
    • Datenabgleich, verschiedene nicht-monetäre Verträge.
  4. Verlassen Sie sich auf einen anderen Vertrag
    • Wenn der Vertrag Eingaben von einem anderen Vertrag akzeptieren oder Transaktionen an einen anderen Vertrag senden muss

Anrufplanung mit Ethereum-Wecker

Der Ethereum-Weckerdienst unterstützt die Planung eines Vertrags, der in der Zukunft zu einem bestimmten Block aufgerufen werden soll. Der zugrunde liegende Mechanismus ist im Wesentlichen eine Abstraktion der obigen anreizbasierten Lösung, die es beliebigen auf privaten Schlüsseln basierenden Konten ermöglicht, einen Anreiz zu haben, Aufrufe zu beliebigen Verträgen auszuführen.

Das Protokoll wurde geprüft und im Mainnet bereitgestellt. Es ist im Moment voll funktionsfähig.

Die Anrufplanung kann mit dem folgenden Code erfolgen:

const { EAC, Util } = require('@ethereum-alarm-clock/lib');
const moment = require('moment');

const web3 = Util.getWeb3FromProviderUrl('ws://localhost:8545');

const eac = new EAC(web3);

async function scheduleTransaction() {
    const receipt = await eac.schedule({
        toAddress: '0xe87529A6123a74320e13A6Dabf3606630683C029',
        windowStart: moment().add('1', 'day').unix() // 1 day from now
    });

    console.log(receipt);
}

scheduleTransaction();

Das obige Beispiel verwendet @ethereum-alarm-clock/lib . Dies ist eine minimale Bibliothek zur Verwendung des Ethereum Alarm Clock-Protokolls.

Weitere erklärende Anleitungen finden Sie hier . Es gibt auch Video-Tutorial .

Ein Teil der Planung des Anrufs besteht darin, ausreichend Ether bereitzustellen, um die zukünftigen Gaskosten für die Ausführung des Anrufs sowie die Zahlungen an den Ausführenden des Anrufs und die Gebühr für die Ersteller des Protokolls (falls angegeben) zu bezahlen.

Wenn dieser Anruf geplant wird, wird ein neuer Vertrag bereitgestellt, der alle Details für die Anrufausführung verwaltet.

Ausführung

Der Alarmdienst benötigt ein auf einem privaten Schlüssel basierendes Ethereum-Konto, um den Anruf zur angegebenen Zeit auszuführen. Dieses Verhalten wird durch einen Zahlungswert motiviert, der jedem geplanten Anruf zugeordnet ist. Bei Eintritt der Zielsperre werden dem Ausführenden des Anrufs seine Gaskosten vollständig erstattet sowie aus dem festgelegten Zahlungsbetrag für seine Leistung bezahlt.

Dieser Prozess der Überwachung des Alarm-Dienstes auf bevorstehende Anrufe und deren Ausführung kann mit TimeNode durchgeführt werden . Jeder kann ein TimeNode sein, hier ist ein umfassendes Tutorial und Video, wie man einer wird: How to Run a TimeNode .

Konfigurierbare Optionen für geplante Anrufe

  • toAddress- Empfängeradresse
  • callData- Transaktionsdaten
  • callGas- Gaslimit für die Transaktionsausführung in der Zukunft
  • callValue- Zukünftiger Transaktionswert in Wei
  • windowSize- Größe des Zeitfensters für die Ausführung in Blöcken oder Sekunden
  • windowStart- Blocknummer / UNIX-Zeitstempel, wann das Fenster zur Ausführung geöffnet werden soll
  • gasPrice- Zukünftiger Gaspreis für die Ausführung
  • fee- Gebühr (in Wei), die an die Betreuer von Ethereum Alarm Clock für die Verwendung der Planung gezahlt wird
  • bounty- Zahlung für den Ausführenden der Transaktion
  • requiredDeposit- Executor Deposit, wenn es versucht, eine geplante Transaktion auszuführen

Kosten

Der Alarmdienst versucht, einen offenen Markt für die Anrufplanung zu schaffen. Der Planer kann einen beliebigen Betrag sowohl für die Prämien- als auch für die Gebührenwerte angeben , und diejenigen, die Anrufe ausführen, können frei wählen, welche Anrufe sie ausführen möchten.

Zum Zeitpunkt der Planung muss ausreichend Ether bereitgestellt werden, um sowohl die Gaskosten als auch die damit verbundenen Zahlungen und Gebühren zu bezahlen. Nach der Ausführung wird jeder verbleibende Ether automatisch an den Planer des Anrufs zurückgegeben.

Testen

Der Alarmdienst steht zum Testen in Testnetzwerken wie Kovan und Ropsten zur Verfügung. Es laufen TimeNodes, die Transaktionen auf diesen Netzwerken ausführen.

Garantien

Der Alarm-Dienst ist ein Marktplatz für Anrufplanung und kann keine Garantie dafür geben, dass ein geplanter Anruf ausgeführt wird. Damit der Dienst funktioniert, müssen Personen die Transaktionen initiieren, die geplante Anrufe ausführen.

Schutz

Als Planer eines Funktionsaufrufs können Sie sich auf Folgendes verlassen:

  • Ihr Vertrag wird mit genau den Verbindungsdaten aufgerufen, mit denen er konfiguriert wurde.
  • Ihr Vertrag wird nicht vor oder nach dem Blockierungsfenster zwischen dem Zielblock und der Anzahl der Blöcke danach, die durch die Nachfrist angegeben ist, gekündigt.

Vertrauenslosigkeit

Der Alarm-Dienst gewährt keiner Partei besondere Berechtigungen und ist zu 100 % Open Source.

Dokumentation und andere Links

Siehe meinen Kommentar zur anderen Antwort. Der erste, der die beiden kombiniert, erhält das Häkchen!
Ich habe oben einen Abschnitt hinzugefügt, der (kurz) das Konzept eines Vertrags anspricht, der bestimmte Aktionen anreizt.
Das ist nah, aber es trifft nicht ganz auf die Antwort von Linagee zu, nämlich dass Sie einen Vertrag oft so umstrukturieren können, dass die "echten" Salden nur auf die neuesten Zahlen aktualisiert werden, wenn jemand sie zum ersten Mal anruft. Ich würde auch gerne eine Beschreibung sehen, wie Entwickler zwischen dem Ansatz der „faulen Bewertung“ und dem Ansatz des Ethereum-Weckers entscheiden sollten, wie ich in meinem Kommentar erwähnt habe.
Sie haben offensichtlich etwas Bestimmtes im Sinn. Ich habe die Antwort veröffentlicht, um als Community-Wiki-Antwort zu gelten. Sie können die Antwort gerne bearbeiten, um das Konzept aufzunehmen, an das Sie denken.
Ich habe einen kurzen Klappentext über Lazy Evaluation und die verschiedenen Optionen hinzugefügt. Ich denke, es braucht jedoch stärkere Beispiele.
Wir können es später immer noch verbessern, aber Sie haben dort den Großteil dessen, wonach ich gesucht habe, also habe ich es als akzeptiert markiert.
Sie behaupten: „Ihr Vertrag wird nicht vor oder nach dem Zeitfenster der Blöcke zwischen dem Zielblock und der Anzahl der Blöcke danach gekündigt, die durch die Nachfrist angegeben ist.“ Was hält jemanden davon ab, den Vertrag jederzeit zu kündigen?
Lebt dieses Projekt noch? Der letzte Commit war [6 Tage her][1], aber die letzte Veröffentlichung war im [Oktober 2016][2]. [1]: github.com/pipermerriam/ethereum-alarm-clock/commit/… [2]: github.com/pipermerriam/ethereum-alarm-clock/releases/tag/…
Seitdem keine Neuigkeiten. Leider sieht es so aus, als wäre dieses Projekt tot.
Ich denke, Ihre Antwort sollte mit der Erwähnung beginnen, dass es keine native Möglichkeit gibt, dies zu tun. Ein intelligenter Kontakt kann sich in Zukunft nicht ohne die Unterstützung eines Dienstes wie Ihrem selbst anrufen. Frage zu Ihrem Codebeispiel – Da die zukünftige Ausführungszeit in Blöcken und nicht in Zeitwerten festgelegt wird, bedeutet dies, dass die tatsächliche zukünftige Ausführungszeit sehr variabel ist, da sie von den spezifischen Blockzeiten aller Blöcke bis zum Ziel abhängt?
Das Projekt lebt und es geht ihm gut. Es wurde in mycrypto.com integriert. Sie können mehr auf ethereum-alarm-clock.com lesen .

Sie könnten den Ethereum-Wecker wie zuvor erwähnt verwenden, aber Sie könnten auch Ihren Programmierstil in ein Paradigma ändern, bei dem ein Anruf ausgeführt werden muss.

Wenn Sie beispielsweise Geld für einen Monat sperren möchten, bis es zurückgegeben wird, können Sie den Benutzer eine Funktion aufrufen lassen, die das Geld dann zurückgibt, anstatt das Geld tatsächlich nach einem Monat zu senden.

Meine ideale Antwort kombiniert diese beiden Top, indem ich erkläre, wann Sie einen Stil und den anderen verwenden sollten. Die Antwort ist übrigens, dass Sie ein Paradigma „muss zum Ausführen aufrufen“ für Operationen verwenden sollten, die nur den Status Ihres eigenen Vertrags betreffen, und Sie sollten den Ethereum-Wecker für Operationen verwenden, die einen Status an anderer Stelle in der Blockchain aktualisieren müssen (der Status von jemandem, der Ihren Vertrag nicht direkt anruft).

Wie andere bereits erwähnt haben, können Sie den Wecker verwenden oder den Ablauf Ihres Vertrags ändern.

Eine andere Möglichkeit ist die Verwendung von Oraclize mit einer leeren Abfrage:

/*
   Simple Alarm code.

   This contract will be called back automatically 1 day after its birth
*/

import "dev.oraclize.it/api.sol";

contract Alarm is usingOraclize {
    function Alarm() {
       oraclize_query(1*day, "URL", "");
    }

    function __callback(bytes32 myid, string result) {
        if (msg.sender != oraclize_cbAddress()) throw;
        // do something, 1 day after contract creation
    }
} 

Es gibt keine formelle Möglichkeit, Ereignisse über das Protokoll selbst zu planen.

Jemand hat jedoch bereits einen Ethereum-Wecker -Vertrag geschrieben, der die Planung von Ereignissen zu einem späteren Zeitpunkt unterstützt. Es ist dezentralisiert, und soweit ich das beurteilen konnte, kann jeder geplante Ereignisse feuern und dafür bezahlt werden.

Sie können in Ethereum keine Cron-Jobs einrichten. Das Protokoll unterstützt diese Art von Operation nicht nativ.

Sie müssen ein Automatisierungsprotokoll verwenden, das auf Ethereum läuft, z . B. Gelato Network .

Aktuell gibt es dafür mehrere Möglichkeiten.

Die Top-Antwort ist alt und Ethereum Alarm Clock war bis vor ein paar Wochen lange ausgefallen und wird jetzt (sieht so aus) vom Chronologic-Team verwaltet.

Ich kopiere hier eine Antwort, da die Community jede andere Antwort zur Planung an diese sendet. Ich füge auch ein Codebeispiel bei, wie man dies mit dem AION-System in Mainnet und Ropsten macht.

## Aion von ETH-Pantheon : Dies ist ein System, das es erlaubt, beliebige Bytecode-Transaktionen zu planen. Das bedeutet, dass Sie eine bestimmte Funktion in einem Vertrag mit bestimmten Daten jederzeit aufrufen oder in Zukunft sperren können.
Vorteile : einfach, erlaubt beliebigen Bytecode, ungenutztes Gas wird zurückgegeben, niedriger Gasverbrauch, vertrauenslos, die Transaktionsgebühr wird a priori definiert, live im Mainnet und in Testnetzen, nette App, Transaktionen können ohne Zahlung jeglicher Klasse storniert werden.
Nachteile : zentralisiert.


##[Chronologic network](https://app.chronologic.network/): Dies ist im Grunde ein Wrap-on-Ethereum-Wecker (Neustart).
**Profis**: dezentralisiert (da es EAC verwendet), erlaubt beliebigen Bytecode, unbenutztes Gas wird zurückgegeben, nette App, live im Mainnet und in Testnetzwerken.
**Nachteile**: teuer im Gas, Gebühr pro Transaktion ist nicht a priori definiert, Scheduler-Knoten müssen ein chronologisches Token halten, außerdem sollte neben der Zahlung an den Ausführenden eine Grundgebühr an den Entwickler des EAC bereitgestellt werden.

## Oraclize : Dies funktioniert, indem eine Callback-Funktion nach einer vom Benutzer ausgewählten Zeitspanne aufgerufen wird. Dann fügen Sie den Code, den Sie ausführen möchten, in diese Funktion ein.
Vorteile: einfach, live im Mainnet und in Testnetzwerken .
Nachteile : zentralisiert, kein beliebiger Bytecode erlaubt, ungenutztes Gas wird nicht zurückgegeben, die Gebühr pro Transaktion kann jederzeit und auf jeden Wert geändert werden, was bedeutet, dass Sie Oraclize vertrauen müssen.


##Joule-System: [mywish.io](https://contracts.mywish.io/create). Dies ist ein dezentrales System zur Planung von Ether-Transaktionen.
**Vorteile**: dezentralisiert, App, Live im Mainnet und Testnetzwerke
**Nachteile**: begrenzte Art von Transaktionen.

Planen von Transaktionen mit dem AION-System.

Im Fall von AION (von ETH Pantheon) ist dies ein Beispiel für die wiederkehrende Planung einer Funktion

\Sie müssen einen externen Dienst für diese Anwendung verwenden, da Smart Contracts von einem externen Konto ausgelöst werden müssen. Das System AION ermöglicht Ihnen dies, Beispiele dafür können Sie hier sehen .

Angenommen, Sie haben einen Smart Contract wie diesen:

contract mycontract{
    uint256 public result;
    function add(uint256 x, uint256 y) public {
        result = x + y;
    } 

}

und Sie möchten diese Summe alle 1 Stunde berechnen (für das Beispiel).

Aion ermöglicht es Ihnen, die Ausführung Ihrer Funktion rekursiv zu planen. Wenn Sie Ihren Vertrag mit AION verbinden, sieht die Lösung wie folgt aus:

pragma solidity ^0.4.24; 

// this is the interface with AION
contract Aion {
    uint256 public serviceFee;
    function ScheduleCall(uint256 blocknumber, address to, uint256 value, uint256 gaslimit, uint256 gasprice, bytes data, bool schedType) public payable returns (uint,address);
    
}


contract MyContract{
    uint256 public result;
    Aion aion;
    
    // This function request to schedule the transaction
    function schedule_add(uint256 x, uint y) public {
        aion = Aion(0xFcFB45679539667f7ed55FA59A15c8Cad73d9a4E);
        bytes memory data = abi.encodeWithSelector(bytes4(keccak256('add(uint256,uint256)')),x,y); 
        uint callCost = 200000*1e9 + aion.serviceFee();
        aion.ScheduleCall.value(callCost)( block.timestamp + 1 hours, address(this), 0, 200000, 1e9, data, true);
    }
    

    // this is your original function
    function add(uint x, uint y) public {
        result = x + y;
    }


    function () public payable {}
    
}

Dies kann auf Ropsten kostenlos getestet werden. (dieses Beispiel ist für ropsten).

Haftungsausschluss: Ich habe den Code für AION geschrieben.

Hoffe das hilft

Ich verwende diesen Code und immer wenn ich versuche, eine Funktionsausführung für die Zukunft durch schedule_add() zu planen, wird meine Transaktion abgelehnt. Ich denke, dies sollte mit der Netzwerküberlastung und den hohen Gasgebühren zusammenhängen. Irgendeine Empfehlung, um meinen Planungserfolg sicherzustellen?

Sie können einen externen Dienst verwenden, um eine Transaktion in der Kette auszulösen, die Ihren Vertrag auslöst.

Dazu können Sie den Chainlink-Wecker verwenden.

Ein vollständiges Beispiel, das einen verzögerten Start von 5 Minuten zeigt, ist unten dargestellt.

pragma solidity ^0.4.24;

import "chainlink/contracts/ChainlinkClient.sol";

contract ChainlinkAlarmClock is ChainlinkClient {

  uint256 oraclePayment;

  constructor(uint256 _oraclePayment) public {
    setPublicChainlinkToken();
    oraclePayment = _oraclePayment;
  }
  function delayStart(address _oracle, bytes32 _jobId) public onlyOwner {
    Chainlink.Request memory req = buildChainlinkRequest(_jobId, this, this.fulfill.selector);
    req.addUint("until", now + 5 minutes);
    sendChainlinkRequestTo(_oracle, req, oraclePayment);
  }
  function fulfill(bytes32 _requestId) public recordChainlinkFulfillment(_requestId) {
    /* additional computation here */
    /* whatever you'd like to do with the delayed start*/
  }
  
}

Dafür gibt es eine nützliche Schnittstelle, mit der Sie diese zeitbasierten Cron-Jobs einfach planen können, ohne einen intelligenten Vertragscode namens „Gelato Ops“ schreiben zu müssen. Haftungsausschluss: Ich habe beim Erstellen der App geholfen :).

Schau es dir hier an:

https://app.gelato.network/

Dort können Sie einfach die Smart-Contract-Adresse und Funktion eingeben, die Sie ausführen möchten, und dann das Zeitintervall auswählen, das bestimmen soll, wann diese Funktion ausgeführt werden soll, wie folgt:

Geben Sie hier die Bildbeschreibung ein

Sie können auch jede andere beliebige Bedingung haben, die Ihre Smart Contracts auslöst, jedoch nicht nur die Zeit.

Sie scheinen Teil des Gelato-Netzwerks zu sein. Die Website hat eine Regel, dass Sie Ihre Zugehörigkeit offenlegen sollten, wenn Sie einen Link in der Antwort verwenden, da dies sonst als Spam betrachtet und gelöscht wird. Kopieren Sie auch nicht dieselbe Antwort und fügen Sie sie ein, sie wird als Spam markiert.
@Ismael Haftungsausschluss hinzugefügt

Eine alternative Lösung, wenn Sie nicht wirklich genau sein müssen, besteht darin, nach ausstehenden geplanten Aufgaben in benutzerinitiierten Transaktionen zu suchen.

Eine einfache Lösung könnte darin bestehen, dass die erste Transaktion in einem beliebigen Block alle ausstehenden Aufgaben verarbeitet:

Sie könnten dies tun, indem Sie den Status der aktuellen Blocknummer beibehalten. Überprüfen Sie zu Beginn einer Transaktion, ob die aktuelle Blocknummer nicht mit dieser Statusvariablen übereinstimmt, was bedeutet, dass wir uns in einem neuen Block befinden. Aktualisieren Sie die Zustandsvariable auf die aktuelle Blocknummer und verarbeiten Sie dann alle ausstehenden Aufgaben. Sie können eine Art Liste ausstehender Aufgaben zusammen mit ihrer frühesten Blocknummer oder ihrem Zeitstempel speichern. Sie können beispielsweise auch nur jeden fünften Block nach ausstehenden Aufgaben suchen. Wenn der Zielblock/die Zielzeit erreicht ist, kann der notwendige Code ausgeführt werden.

Vorteile:

  • Keine zentralisierte Fehlerquelle
  • Keine Notwendigkeit, Gasgebühren im Voraus zu zahlen (obwohl Sie die Möglichkeit haben, eine Vorauszahlung zu verlangen, wenn Sie möchten)
  • Es ist nicht möglich, versehentlich zu wenig Gasgebühren zu zahlen und Ihre Aufgabe abzubrechen

Nachteile:

  • Code kann später als zur Zielzeit ausgeführt werden, wenn keine Transaktionen auf Ihrem Smart Contract stattfinden
  • Der unglückliche Händler, der zuerst im Block ist, muss Gas bezahlen, um ausstehende Transaktionen zu verarbeiten. Dies kann kompensiert werden, indem ein Teil oder das gesamte Gas aus Reserven bezahlt wird, die der Smart Contract besitzt, oder indem dieser unglückliche Händler mit einem benutzerdefinierten Token belohnt wird.