Ich habe mir etwas Zeit genommen, um das Upgrade-Handbuch für das Newton-Protokoll durchzulesen, und immer wieder bin ich bei einem Implementierungsdetail gelandet: Neue Speichervariablen werden immer an das bestehende Speicherlayout angehängt, statt in dieses eingefügt zu werden.
Das klingt fast schon trivial
Ich glaube, das ist es nicht
Ich habe schon erlebt, dass upgradefähige Contracts kaputtgehen, weil jemand das Storage-Layout falsch eingeschätzt hat. Das Proxy-Upgrade besteht die Tests, alles sieht in Ordnung aus, und dann entdeckt man Wochen später, dass eine Variable überschrieben wurde, weil sich die Reihenfolge im Speicher geändert hat. Das ist ein Chaos. Der Contract schlägt nicht unbedingt sofort fehl. Manchmal fängt er einfach an, sich anders zu verhalten – was viel schwerer zu diagnostizieren ist.
Das Newton-Protokoll vermeidet diese Falle, indem es das Speicher-Layout als etwas behandelt, das erhalten werden sollte, statt es umzubauen. Ich mag diesen Ansatz, weil er berücksichtigt, wie fragil upgradefähige Proxies sein können.
Ein weiteres Detail, das mir aufgefallen ist, ist das Flag newtonPolicyClientInitialized. Sein Zweck ist einfach: Die Initialisierung nach dem Upgrade kann nur einmal stattfinden. Das Newton-Protokoll empfiehlt außerdem, Upgrades auf einem Fork zu testen und beim Ausführen der Initialisierungs-Transaktion einen Timelock oder ein Multisig zu verwenden. Das wirkte nicht wie eine Standard-Ratschlagsschablone auf mich. Es fühlte sich an wie eine Anerkennung, dass das Upgrade nicht abgeschlossen ist, wenn die neue Implementierung bereitgestellt wurde.
Die Initialisierung ist Teil des Upgrades.
Bis dieser Schritt abgeschlossen ist, kann die Autorisierungslogik zwar bereits im Vertrag vorhanden sein, aber der Policy-Client ist noch nicht mit dem richtigen TaskManager verbunden oder dem vorgesehenen Policy-Client-Owner zugewiesen. Wenn einer der Werte falsch ist, kann die Autorisierungsebene fehlschlagen, obwohl die Bereitstellung selbst erfolgreich zu sein schien.
Deshalb denke ich, dass das Einmal-Initialisierungs-Flag so wichtig ist.
Es verhindert, dass jemand die Initialisierung erneut ausführt, aber es schützt nicht davor, die erste Ausführung falsch zu machen. Wenn die anfängliche Konfiguration Fehler enthält, behebt das Einklemmen hinter einem Einmal-Flag diese nicht magisch. Es macht nur die erste Ausführung zu einem der sensibelsten Momente in der gesamten Bereitstellung.
Ich habe außerdem bemerkt, dass das Newton-Protokoll nicht jede Konfiguration nach der Initialisierung dauerhaft einfriert. Der Owner des Policy-Clients kann weiterhin Richtlinieneinstellungen aktualisieren, die Adresse des Policy-Vertrags ändern und später den Ownership übertragen. Ich bevorzuge das tatsächlich gegenüber der Annahme, dass sich Systeme nie weiterentwickeln müssen. Änderungen an der Infrastruktur. Änderungen in der Governance. Änderungen der Anforderungen. Die Herausforderung besteht darin, sicherzustellen, dass diese Berechtigungen auch im Zeitverlauf gut kontrolliert bleiben. Die Speicherkompatibilität schafft ganz eine andere Kategorie von Risiko.
Eines, das ich am Newton-Protokoll schätze, ist, dass es Teams ermöglicht, die Durchsetzung von Policies einzuführen, ohne ihre Anwendung komplett von Grund auf neu aufbauen zu müssen. Das ist eine praktische Designentscheidung. Aber das Proxy-Upgrade muss die Speicherkompatibilität exakt bewahren: Setzt man eine Variable an der falschen Position ein, kann die Autorisierungsebene völlig gesund aussehen, während der nicht zusammenhängende Anwendungsstatus darunter still und heimlich beschädigt wird.
Ich habe genug upgradefähige Systeme gesehen, um zu wissen, dass das kein hypothetisches Problem ist.
Ein weiterer Aspekt, der nicht übersehen werden sollte, ist der Ausführungsablauf: Das Hinzufügen einer neuen Newton-geschützten Funktion sichert nicht automatisch eine ältere Funktion ab, die dieselbe Aktion ausführt. Jeder Pfad, der eine Autorisierung erzwingen soll, muss weiterhin validateAttestation oder validateAttestationDirect aufrufen, bevor die geschützte Business-Logik ausgeführt wird. Verpasst man einen Ausführungspfad, schafft man unbemerkt inkonsistente Sicherheitsgarantien.
Wahrscheinlich ist das das, was ich am interessantesten am Newton-Protokoll fand.
Die Architektur trennt den NewtonPolicyClient.
aus der Business-Logik der Anwendung heraus, statt Entwickler zu zwingen, alles rund um ein neues Framework neu zu designen. Ich bevorzuge generell diesen modularen Ansatz, weil große Systeme selten von Grund auf neu geschrieben werden. Sie entwickeln sich Upgrade für Upgrade.
Gleichzeitig frage ich mich jedoch, ob das Risiko sich tatsächlich einfach auflöst.
Oder ob es einfach nur verschiebt.
Das Newton-Protokoll macht die Autorisierung einfacher in bestehende upgradefähige Verträge zu integrieren. Das halte ich für wertvoll. Aber dadurch werden das Proxy-Upgrade, die Speicher-Migration und der allererste Initialisierungsaufruf zu den Stellen, an denen sich das größte operative Risiko konzentriert.
Ich sehe das nicht als Schwäche des Designs.
Ich sehe das als eine Erinnerung daran, dass gute Architektur schwierige Entscheidungen nicht eliminiert – sie macht sie normalerweise nur leichter zu erkennen.
Jedes Upgrade ändert den Code, aber nicht jedes Upgrade stärkt die Sicherheit. Für mich zeigt das Newton-Protokoll, dass die kleinsten Implementierungsdetails oft die größte Wirkung haben, wenn es darum geht, robuste Smart Contracts aufzubauen.
