cryptofoundry

cryptofoundry kontaktieren

Sagen Sie uns, was Sie bauen oder automatisieren möchten.

Developers & API

Transaktionsveröffentlichung, Normalisierung, Verifizierung und Broadcast auf ADAMANT-Knoten

Funktionen

Transaction.prototype.verify prüft eine aus anderen Blöcken abgerufene Transaktion, die möglicherweise auch alte Transaktionen umfasst. Transactions.prototype.publish prüft eingehende Transaktionen von Nutzern und verifiziert frische, unbestätigte Transaktionen. verify wird außerdem nach dem Empfang einer neuen Transaktion über die API aufgerufen, nachdem die Methoden publish und objectNormalize durchlaufen wurden. publish wird nur aufgerufen, wenn Transaktionen über die öffentliche API gesendet werden.

Transaktionsverarbeitung

Wenn ein Knoten über die API eine neue Transaktion von einer Client-App erhält und der erste Knoten ist, der sie sieht, erstellt Logic->Transaction.prototype.publish eine neue Transaktion aus den empfangenen Daten, validiert die Eigenschaften der Client-Transaktion (einschließlich timestampMs), fügt eine Transaktions-ID hinzu und verarbeitet die unbestätigte Transaktion wie üblich. Wenn ein Knoten eine neue Transaktion von einem anderen Peer auf der aktuellen Höhe erhält, validiert er die Transaktion und entfernt den Peer, falls sie ungültig ist, und verarbeitet anschließend die unbestätigte Transaktion. Beim Abrufen einer Transaktion von einem anderen Peer während des Hochfahrens oder bei der Verifizierung der Blockchain ab Höhe 0 validiert der Knoten die Transaktion, entfernt den Peer bei Ungültigkeit und verarbeitet die unbestätigte Transaktion, während mehrere Transaktionen gleichzeitig verifiziert werden. Die Validierung umfasst den Aufruf von objectNormalize() zur Schema-Validierung der empfangenen Transaktion.

Der Ablauf zur Verarbeitung unbestätigter Transaktionen beginnt mit logic.transaction.process(), das die Transaktions-ID verifiziert und die Absender-ID normalisiert. Danach wird die Transaktion normalisiert: logic.transaction.objectNormalize() validiert das Transaktionsobjekt gemäß einem Schema und entfernt unnötige Eigenschaften, einschließlich timestampMs vor der Aktivierung von spaceship. Schließlich wird logic.transaction.verify() aufgerufen, um alle Eigenschaften wie timestamp, timestampMs und signature zu verifizieren.

Das Entfernen eines Peers bedeutet, dass er aus der Peer-Liste gelöscht wird, bis er erneut entdeckt wird; Knoten sperren Peers nicht, daher wird der Status BANNED niemals vergeben. Ein Knoten sendet eine Transaktion an andere Knoten, nachdem die unbestätigte Transaktion verarbeitet wurde. Neben objectNormalize() verfügt der Knoten über normalize(), das nur für den POST /transactions/normalize-Endpunkt verwendet wird, der veraltet sein sollte. Der Knoten verfügt sowohl über apply() als auch applyUnconfirmed(), da sich „apply“-Methoden auf die Kontostände von Absender und Empfänger auswirken, während applyUnconfirmed() nur den unbestätigten Kontostand ändert; dasselbe gilt für die „undo“-Methoden. Wenn ein Knoten einen neuen Block generiert, werden die Transaktionen aus einer bereits verifizierten Liste entnommen. Derzeit prüft publish(), ob der Transaktions-Timestamp in der Zukunft liegt oder mehr als constants.maxTransactionAgeSec Sekunden in der Vergangenheit. Es ist nicht sinnvoll, dieselben Prüfungen in publish wie in verify einzufügen, da letzteres nach publish aufgerufen werden muss. Außerdem können die Prüfungen von publish nicht in verify integriert werden, da sie von der aktuellen Zeit abhängen, wodurch es unmöglich wird zu überprüfen, ob eine alte Transaktion nicht älter als 5 Sekunden ist. Eine Client-App erhält Fehlermeldungen wie The difference between timestamp and timestampMs is greater than ${maxTimestampMsDelta}ms. oder Invalid transaction timestamp. Timestamp is not in the int32 range, wenn diese Prüfungen nicht in publish(), sondern in verify() erfolgen.

Hinweise zu Timestamps

Der Transaktions-Timestamp ist die ADAMANT-Epoche in Sekunden, nicht Unix-Zeit. Der Transaktions-TimestampMs sollte die ADAMANT-Epoche in Millisekunden sein, nicht Unix-Zeit; Unix-Millisekunden können berechnet werden als constants.epochTime.getTime() + timestampMs. Das Feld timestampMs ist kein Bestandteil der Transaktionsbytes, Signaturen, Transaktions-IDs oder Hashes, auch nicht nach der spaceship-Aktivierung. Nach spaceship sollte die konsensrelevante Validierung verlangen, dass timestampMs in derselben ADAMANT-Epochen-Sekunde wie timestamp liegt: 0 <= timestampMs - timestamp * 1000 < 1000. Diese strengere Regel für dieselbe Sekunde ist beabsichtigt: timestampMs muss genau dieselbe ADAMANT-Epochen-Sekunde verfeinern, die in timestamp gespeichert ist, und Clients sollten timestamp = Math.floor(timestampMs / 1000) berechnen. Die Verwendung von Math.round() oder Math.ceil() nahe einer Sekundengrenze erzeugt inkonsistente Paare und sollte abgelehnt werden. Eine Überprüfung aktueller Clients und Quellen ergab, dass adamant-api-jsclient, die PWA, adamant-console (über [email protected]), iOS und Dokumentationsbeispiele alle Math.floor oder äquivalente Abschneidung verwenden, und kein ausgehender ADM-Transaktions-Timestamp-Generierungs-Pfad verwendet round oder ceil. Vor spaceship sollte die konsensrelevante Normalisierung timestampMs entfernen, damit das Verhalten vor der Aktivierung mit älteren Knoten kompatibel bleibt. Mehrere Transaktionen desselben Absenders innerhalb einer Sekunde sind erlaubt, solange es sich um unterschiedliche Transaktionen handelt; timestampMs hilft Clients dabei, schnelle Chatnachrichten zu sortieren, darf aber nicht als Transaktions-Nonce oder Signatur-Eingabe verwendet werden.

Prüfungen zum Zeitpunkt der Aufnahme

Die Methode publish() enthält Aufnahmeprüfungen über die öffentliche API für frisch eingereichte Transaktionen, die von der aktuellen Uhrzeit des Knotens abhängen können. Wenn eine Transaktion publish() besteht, wird sie dennoch von verify() verarbeitet, das absichtlich keine Prüfung der aktuellen Zeit enthält und nur deterministische Prüfungen wie Schema, ID, Signaturen, Kontostände und die timestampMs-Regel für dieselbe Sekunde beibehalten sollte. Zeitabhängige Prüfungen aus publish() dürfen nicht in verify() verschoben werden, da verify() für Wiedergabe, Synchronisation und historische Transaktionen verwendet wird. Die bestehende Zukunftsprüfung ist slotbasiert: Bei 5-Sekunden-Slots tritt der Fehler Transaction timestamp is in the future nur auf, wenn ein um etwa 400 ms vorgestellter Client-Uhrzeit der gerundete Sekunden-Timestamp in den nächsten Slot fällt. maxTransactionFutureMs ist eine nicht-konsensrelevante Toleranz für die API-Aufnahme, die nur in publish() angewendet wird, nicht jedoch bei Wiedergabe, Peer-/Block-Verifizierung oder Konsens-Aktivierungslogik. Die vorgesehene Bedingung bewahrt die alte slotbasierte Aufnahmerichtlinie, während der Grenzfall abgemildert wird, indem nur dann abgelehnt wird, wenn transactionSlotNumber > currentSlotNumber und die Transaktionszeit mehr als maxTransactionFutureMs vor der aktuellen Zeit des Knotens liegt. Für diese Berechnung sollte timestampMs verwendet werden, wenn der Client es bereitstellt; andernfalls wird auf timestamp * 1000 zurückgegriffen. Eine kleine nicht-konsensrelevante Toleranz in publish() (z. B. 500 ms für den nächsten Slot) kann die Benutzerfreundlichkeit für leicht vorgestellte Client-Uhren verbessern, ohne die Wiedergabe-Validierung zu verändern, obwohl Client-Apps dennoch einen kleinen Zeitpuffer für die Kompatibilität mit älteren Knoten beibehalten sollten. Eine Transaktion, deren timestamp eine Sekunde vor der aktuellen Blockzeit liegt, kann dennoch in diesen Block aufgenommen werden, ohne die Blockchain zu beschädigen, da der Transaktions-timestamp signierte Transaktionsmetadaten ist und nicht die Gültigkeit von Slot oder Block bestimmt, und der Konsens verlangt nicht tx.timestamp <= block.timestamp. Während der Wiedergabe vergleichen Knoten Transaktions-Timestamps nicht mit der lokalen Echtzeit, daher kann die Aufnahme-Toleranz keine Wiedergabe-Divergenz verursachen.

Status-Endpunkt

Der Endpunkt /api/node/status kann zusätzliche Uhr-Felder wie nodeTimestampMs (ADAMANT-Epoche in Millisekunden) und unixTimestampMs ohne Konsens-Auswirkungen zurückgeben. nodeTimestamp bleibt die ADAMANT-Epoche in Sekunden.

Aktivierungshöhen

Konsens-Aktivierungshöhen sollten für Testnet und ADAMANT-basierte Ketten konfigurierbar sein, während die Mainnet-Standardwerte im Code oder in der Konfiguration erhalten bleiben. Die historische Prüfung fairSystemActivateBlock: 4359464 verwendete height > fairSystemActivateBlock, daher ist die äquivalente erste aktive Höhe für eine benannte fairSystem-Aktivierung 4.359.465. Die spaceship-Aktivierung sollte nur konsensrelevantes Verhalten steuern, wie das Akzeptieren, Normalisieren, Speichern und Validieren von timestampMs während der Block-, Peer- und Wiedergabe-Verarbeitung. Zeitbezogene publish()-Prüfungen sind Aufnahmerichtlinien und sollten außerhalb der Konsens-Aktivierung bleiben.