
Im letzten Artikel
„Autonome Agenten“ oder wenn wir den Code in der offenen Kryptoplattform von Obyte ausführen, haben wir darüber gesprochen, was autonome Agenten sind, und sie mit intelligenten Verträgen von Ethereum verglichen. Schreiben wir nun unseren ersten autonomen Agenten (AA) anhand des 51% Attack-Beispiels. Und am Ende des Artikels werden wir Möglichkeiten zur Verbesserung analysieren: Wie können Spieler vor dem Verlust / Verlust von Geldern geschützt werden und wie kann der Algorithmus verbessert werden, um die Auswirkung von „Walen“ mit großen Einzahlungen auf das Spielergebnis zu verringern.
Die Originale beider eigenständiger Agenten sind im
Online-Oscript-Code-Editor immer in Form von Vorlagen
verfügbar. Wählen Sie sie einfach aus dem Dropdown-Menü aus:
„51% Angriffsspiel“ und
„Fundraising-Proxy“.Bevor Sie mit dem Schreiben von AA in Oscript beginnen, empfehle ich dringend, den
Leitfaden Erste Schritte (deu) in unserer Dokumentation zu lesen, um sich schnell mit den Grundprinzipien des Schreibens von AA vertraut zu machen.
Die Essenz des Spiels
Mehrere Teams konkurrieren gleichzeitig um das Recht, den gesamten Pool gesammelter Gelder zu sammeln. Teamplayer machen Einzahlungen und erhöhen dadurch den Gesamtbetrag des Pools. Das Team, das mindestens 51% aller eingenommenen und mindestens einen Tag lang als Leader gehaltenen Gelder eingezahlt hat, gewinnt. Der Pool wird proportional zum geleisteten Beitrag auf die Spieler des Gewinnerteams verteilt, wodurch jeder Teilnehmer möglicherweise seine Investition verdoppeln kann.
Sobald eines der Teams> = 51% aller Gelder sammelt, wird es zuvor zum Gewinner erklärt und seine Teilnehmer können keine Einzahlungen mehr tätigen. Alle anderen Teams haben 24 Stunden Zeit, um das Gewinnerteam zu überholen. Sobald dies geschieht, wird das überholende Team der Gewinner und der Timer startet den Countdown erneut.
Unsere Implementierung gibt "Aktien" an jeden Einzahler im Austausch gegen Bytes im Verhältnis 1: 1 aus. Wenn das Team gewinnt, kann der Teilnehmer gegen eine Aktie im gewonnenen Pool tauschen. Aktien sind ein Aktivposten auf der Obyte-Plattform, der speziell für jedes Team freigegeben wurde. Sie können wie jeder Vermögenswert übertragen / gehandelt werden und ihre potenziellen Gewinne an andere Personen verkaufen. Der Aktienkurs hängt vom Markt ab, der die Gewinnchancen des Teams bewertet.
Jeder kann ein Team bilden. Der Schöpfer des Teams kann eine Gewinnprovision festlegen, die im Falle eines Sieges von jedem Teammitglied berechnet wird.
Wir werden auch die zweite AA in unserem Spiel im Namen des Erstellers des Teams anwenden, der den erforderlichen Betrag „Crowd Funding“ durchführt. Nur wenn dies erreicht ist (in unserem Beispiel bei Erreichen von> 51% des Spielpools), werden alle gesammelten Mittel an die Adresse AA gesendet Spiele, sonst kann das Geld frei zurückgenommen werden.
Schreiben von Oscript-Code
Ich möchte Sie daran erinnern, dass der AA-Code jedes Mal aufgerufen wird, wenn eine Transaktion an der Adresse dieses AA eingeht, der sogenannten Transaktion auslösen. Tatsächlich ist AA ein Code, der als Antwort auf eine Eingabe (Daten in einer Triggertransaktion und der aktuelle Status von AA selbst, gespeichert in Statusvariablen) eine Ausgabe generiert (eine andere "Antwort" -Transaktion) oder ihren Status ändert. Unsere Aufgabe ist es, die Regeln der AA-Reaktion auf Eingabedaten zu programmieren. Alle Transaktionen in Obyte sind eine Reihe von Nachrichten, meistens sind es "Zahlungs" -Nachrichten oder "Daten" -Nachrichten usw.
Initialisierung
Zuerst initialisieren wir unsere AA. Der Init-Block wird bei jedem Start von AA ganz am Anfang aufgerufen. Darin setzen wir lokale Konstanten für einen bequemeren Zugriff auf Werte.
{ init: `{ $team_creation_fee = 5000; $challenging_period = 24*3600; $bFinished = var['finished']; }`, messages: { cases: [ ] } }
String
$ bFinished = var ['beendet']; liest die
fertige Variable aus dem Zustand AA.
Ein Array der resultierenden Nachrichten wird von den
Fällen umrahmt
: {} Block, der dem üblichen
Schalter- / Fall- / Standardblock ähnelt, basierend auf den Bedingungen in den if-untergeordneten Blöcken, wird nur eine der Nachrichten ausgewählt, oder wenn nein,
wenn Blöcke
true zurückgeben , wird dies der Fall sein letzte ausgewählte Nachricht.
Wir bilden ein Team
Der erste Block verarbeitet also Transaktionen, um einen neuen Befehl zu erstellen:
Wie wir sehen, ist die Bedingung für die Ausführung dieses Blocks die erste im if-Block und eine Überprüfung, ob die Triggertransaktion eine Nachricht mit dem Datentyp (
trigger.data.create_team ) enthält, die einen Schlüssel namens
create_team hat Das Spiel ist noch nicht vorbei (
! $ bFinished ). Auf die lokale Konstante
$ bFinished kann von überall im Code
zugegriffen werden, wenn sie im Init-Block initialisiert wurde. Wenn mindestens eine dieser Bedingungen nicht erfüllt wäre, würde der übergeordnete Fallblock einfach weiter ausgeführt und die Bedingungen für die folgenden Nachrichten überprüft, wobei diese übersprungen würde.
Im nächsten
Init- Block initialisieren wir nichts, sondern überprüfen die notwendigen Bedingungen, ohne die die Trigger-Transaktion als fehlerhaft angesehen wird:
if (var['team_' || trigger.address || '_asset']) bounce('you already have a team'); if (trigger.output[[asset=base]] < $team_creation_fee) bounce('not enough to pay for team creation');
Hier verketten wir (mit ||) die Zeichenfolge mit der Variablen aus dem Transaktionsauslöser und versuchen herauszufinden, ob es eine Variable mit dem Namen
'team_' || gibt trigger.address || '_asset' in unserer AA-Geschichte.
Der Aufruf von
bounce () setzt alle am aktuellen Moment vorgenommenen Änderungen zurück und gibt einen Fehler an den Aufrufer zurück.
Beachten Sie auch, wie die Suche innerhalb der Triggertransaktion
ausgeführt wird :
trigger.output [[Asset = Basis]] sucht nach einer Ausgabe mit
Asset == Basis , die den in der Triggertransaktion angegebenen Betrag in Bytes (Basis-Asset = Bytes) zurückgibt. Und wenn dieser Betrag nicht ausreicht, um ein neues Team zu erstellen, rufen wir bounce () auf und essen stillschweigend alle eingehenden Bytes abzüglich bounce_fee, was standardmäßig 10.000 Bytes beträgt.
Als nächstes beginnt der Großteil des Teambuilding-Codes. Kurz gesagt lautet der Algorithmus wie folgt:
- Die erste Nachricht gibt ein neues Asset frei ( App: 'Asset' )
- Die zweite Nachricht gibt alles zurück, was mehr als die zum Erstellen des Befehls erforderliche Anzahl von Bytes ist ( App: 'Zahlung' ). Schauen Sie sich hier den if-Block an. Wenn diese Bedingung falsch ist (der Ersteller hat genau die erforderliche Anzahl von Bytes gesendet), wird diese Nachricht nicht in die resultierende Transaktion aufgenommen, sondern einfach verworfen.
- Die dritte Nachricht ändert den Status unserer AA ( App: 'state' ): Wir schreiben die als Argument übergebene Gründersteuer oder setzen sie auf 0, wenn sie nicht an die Triggertransaktion übertragen wurde. Das var1- Konstrukt gibt andernfalls var2 var1 zurück, wenn es in true umgewandelt wird, andernfalls gibt es var2 zurück. Hier treffen wir auf die Variable response_unit, die immer den Hash der resultierenden Einheit enthält. In diesem Fall, weil Die resultierende Einheit erstellt ein neues Asset namens Asset-a und ist der Hash der erstellenden Einheit. Die Zeichenfolge response ['team_asset'] = response_unit schreibt einfach denselben Hash (oder das Asset für den angegebenen Befehl) in das Array responseVars in der letzten Einheit. Das Antwortarray kann auch der Person vorgelesen werden, die die Auslösetransaktion durchgeführt hat, sowie in Ereignis-Listenern, die Ereignisse mit dieser AA abonniert haben.
Wir akzeptieren Einzahlungen
Wenn die Erstellung des Teams abgeschlossen ist, fahren Sie mit dem nächsten Block fort - Verarbeitung der Einzahlungen von Teammitgliedern.
Von dem neuen, das wir hier treffen, ist die Ausgabe von Token des Vermögens des ausgewählten Teams an seinen Teilnehmer im Austausch für seine Einzahlung in Bytes:
asset: `{var['team_' || trigger.data.team || '_asset']}`, outputs: [{address: "{trigger.address}", amount: "{trigger.output[[asset=base]]}"}
Wie wir uns erinnern, die Zustandsvariable
'team_' || trigger.data.team || Wir haben das
'_asset' in der Phase der
Teamerstellung gespeichert und es speichert den Hash der Einheit, in der wir das Asset für dieses Team erstellt haben,
dh den Namen dieses Assets - a.
Im selben Block wird die Hauptbedingung auf 51% überprüft:
if (var['team_' || trigger.data.team || '_amount'] > balance[base]*0.51){ var['winner'] = trigger.data.team; var['challenging_period_start_ts'] = timestamp; }
Wenn nach dieser Auslösetransaktion der Kontostand des angegebenen Teams 51% überschreitet, wird das Team zum Gewinner erklärt und wir zeichnen den aktuellen Unix-Zeitstempel auf (starten Sie den Timer).
Dieser Zeitstempel wird im dritten Block überprüft, wenn wir eine Auslösetransaktion mit dem Versuch erhalten, das Spiel zu beenden:
Wir zahlen einen Preis
Und der letzte Block, der am meisten Spaß macht, ist die Zahlung der gesamten Anzahlung an die Gewinner:
Interessant ist hier der Initialisierungsblock, in dem wir die notwendigen Werte im Voraus berechnen:
$share = $asset_amount / var['team_' || $winner || '_amount']; $founder_tax = var['team_' || $winner || '_founder_tax']; $amount = round(( $share * (1-$founder_tax) + (trigger.address == $winner AND !var['founder_tax_paid'] ? $founder_tax : 0) ) * var['total']);
Alle Mitglieder des Teams mit Ausnahme des Erstellers erhalten einen Betrag, der proportional zu ihrem ursprünglichen Beitrag ist (1-mal-1-Byte im Austausch für Asset-Token, die in einer Auslösetransaktion gesendet werden). Dem Ersteller wird auch eine Provision gezahlt (es wird überprüft, ob die Adresse der
Person , die die Auslösetransaktion gesendet hat, der Adresse des Erstellers des Gewinnerteams
trigger.address == $ Gewinner entspricht ). Es ist wichtig, nicht zu vergessen, dass die Provision nur einmal gezahlt werden sollte und der Ersteller unendlich viele Triggertransaktionen senden kann. Daher speichern wir das Flag im Status AA.
Starte das Spiel
Der Code ist also fertig. Hier ist eine vollständige Auflistung davon:
vollständiger AA-Code { init: `{ $team_creation_fee = 5000; $challenging_period = 24*3600; $bFinished = var['finished']; }`, messages: { cases: [ {
Lassen Sie uns den Code auf Gültigkeit prüfen und versuchen, ihn in testnet bereitzustellen.
- Gehen Sie zum Online-Editor: https://testnet.oscript.org
- Fügen Sie unseren Code ein und klicken Sie auf Validieren. Wenn alles korrekt ist, sehen wir eine Berechnung der Codekomplexität: AA validiert, Komplexität = 27, ops = 176 . Hier ist ops die Anzahl der Operationen in unserem Code, Komplexität ist die Komplexität des Codes. Obyte-AAs haben keine Zyklen, aber selbst dies ermöglicht keinen 100% igen Schutz des Netzwerks vor böswilligen AAs mit schlechtem Code. Daher haben alle AAs eine Obergrenze für die Komplexität, Komplexität = 100. Die Codekomplexität wird zum Zeitpunkt der Bereitstellung berechnet und alle Zweige des Codes werden berücksichtigt. Einige Operationen sind relativ einfach, z. B. ± und andere. Sie erhöhen die Komplexität nicht. Andere, wie der Zugriff auf die Datenbank (Änderung des Status) oder komplexe Berechnungen (Aufruf einiger Funktionen), erhöhen die Komplexität. Informationen dazu, welche Vorgänge einfach und welche komplex sind, finden Sie in der Sprachreferenz .
- Klicken Sie auf Bereitstellen. Wir sehen etwas Ähnliches
Check in explorer: https://testnetexplorer.obyte.org/#DiuxsmIijzkfAVgabS9chJm5Mflr74lZkTGud4PM1vI= Agent address: 6R7SF6LTCNSPLYLIJWDF57BTQVZ7HT5N
Ich rate Ihnen, dem Link im Explorer zu folgen und sicherzustellen, dass das Gerät mit unserer AA im Netzwerk verfügbar ist. Der Explorer zeigt auch den vollständigen Code für unsere AA an Alle AAs im Obyte-Netzwerk sind Open Source. Sie können den Code eines Agenten an seiner Adresse studieren.
Crowdfunding
Und nun zu den versprochenen Optimierungen. In der aktuellen Implementierung sendet jeder Spieler sofort Geld an die AA-Adresse des Spiels und gibt sein Team an. Gleichzeitig wird das Team möglicherweise nie zum Anführer, und das Geld wurde bereits gesendet. Wir können den Prozess des Geldsammelns optimieren und die Situation vermeiden, dass wir Geld an ein Team senden, das niemals ein Gewinner wird. Dies kann mit der zweiten AA erfolgen, indem das sogenannte Crowdfunding von Geldern arrangiert wird, indem ein dynamisches Ziel für den Betrag der gesammelten Mittel festgelegt wird, der 51% des Betrags im Spiel entspricht.
In Oscript können wir den Status jeder anderen AA lesen, sodass wir die Möglichkeit haben, ein dynamisches Ziel in unserer Crowdfunding-AA festzulegen.
Der Algorithmus lautet wie folgt: Der Ersteller des Teams fordert die Spieler auf, Geld nicht an die Adresse des Spiels, sondern an die Adresse eines Agenten zu senden, der die Crowdfunding-Funktionalität implementiert. Dieser Agent speichert die gesammelte Menge an Bytes zu Hause und sendet sie nur dann an das Spiel, wenn er> = 51% der Menge im Spiel sammelt. Und sofort wird dieses Team führend. Wenn der erforderliche Betrag nicht eingezogen wird, wird das Geld einfach an die Spieler zurückgegeben. In der Phase des Fundraising erhalten die Spieler keine Team-Spiel-Token, sondern Crowdfunding-Token, die bei Erfolg in Zukunft zurückerstattet oder gegen Spiel-Token eingetauscht werden können.
Im nächsten Artikel implementieren wir diese Funktionalität.
Wir sammeln keine Bytes, sondern Zertifizierungen
In der einfachsten Form des Spiels "Attack 51%" sprechen wir über die Höhe der gesammelten Mittel. So können „Wale“ mit großen Geldbörsen den größten Teil der Gewinne erzielen.
Um das Spiel für alle Teilnehmer ehrlicher zu gestalten, werden wir versuchen, nicht die Anzahl der gesendeten Bytes, sondern die Anzahl der Teilnehmer in den Teams zu zählen. Das Team, das die maximale Teilnehmerzahl gewinnen konnte, gewinnt. Jeder Spieler investiert einen festen Betrag, beispielsweise 1 GB, und zählt als Einheit in den Teampool. Nichts hindert uns jedoch daran, eine unendliche Anzahl neuer Adressen zu erstellen. Die kritische Bedingung ist daher, dass im Spiel nur Adressen zulässig sind, die mit anderen IDs verknüpft sind, wobei die Regel „Eine Person - eine ID“ eingehalten wird. Eine solche Bindung wird als
Zertifizierung bezeichnet . Ein Beispiel für eine Zertifizierung ist die Weitergabe des KYC-Verfahrens. Anschließend wird an die DAG eine Nachricht über die Verbindung zwischen der Obyte-Adresse und dem Hash personenbezogener Daten gesendet (die personenbezogenen Daten selbst werden in der Brieftasche des Benutzers gespeichert und er kann sie an einzelne Gegenparteien weitergeben, wenn er dies wünscht. Für diese Aufgabe sind sie jedoch nicht erforderlich nur die Tatsache der Bindung). Ein weiteres Beispiel für die Zertifizierung ist die Zertifizierung von E-Mails in Domänen, in denen die Regel „Eine Person - eine E-Mail“ eingehalten wird, z. B. in Domänen einiger Universitäten, Unternehmen und Länder. Somit wird eine reale Person nur einmal gezählt.
Autonome Agenten können den Status der Zertifizierung von Adressen im Netzwerk anfordern, sodass eine minimale Anzahl von Änderungen am Code vorgenommen wird.
Ich schlage vor, dass die Leser in den Kommentaren vorschlagen, an welchen Stellen und wie genau es notwendig ist, die Codezeilen der aktuellen Version des Spiels zu ändern, um dies zu implementieren. Um wie immer die
Oscript-Sprachreferenz zu unterstützen .
Unsere
Zwietracht &
Twitter