feat(pesos): spec 20, los 17 pesos del gobierno salen de los certificados de Laurha
Ya no queda ningun smoke de Charon. weights.rs se ENSAMBLA desde los tres certificados del banco de referencia (la Pi 5) con scripts/bench/ensamblar-pesos.py: - Cada funcion cobra el maximo, coeficiente a coeficiente, de todos los certificados que midieron su mismo codigo (mismo esqueleto de lecturas, escrituras y proof que el del ultimo, que es el del codigo que corre). - Con --comprobar dice si el fichero es exactamente ese ensamblado: probado en rojo cambiando a mano un peso. - Los tres certificados quedan en scripts/bench/certificados/ (sha256 18b8fcd6, 1e15d04e y 6f5cfec1), con su perfil y su evidencia en la cabecera. Por que el maximo de todos y no solo el ultimo: «El maximo de 5 de un dia no es el de otro» (Laurha). La revision adversaria de spec 20 encontro que cobrar solo el certificado vigente de cada funcion dejaba treasury_disbursement en 136 us, cuando el certificado del 2-nov, sobre el wasm que corre, mide 155 us, y otros siete por debajo de lo medido. Con la regla, ningun peso baja respecto a spec 19; los que suben, entre el +1 % y el +33 % de ejecucion. Probado: - 365 tests verdes. - Ensayo en la rp1 sobre una cadena con el codigo vivo de spec 19. Contrafactual: con estos pesos, el E2E reprueba contra spec 19, porque la cadena cobra los viejos. Tras el upgrade a 20 pasa entero, y lo cobrado es weights.rs + extensiones. Ademas: configs.rs ya no dice «Weights INTERIM hand-derived» en los cinco pallets, que cobran pesos certificados desde spec 17. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
158060bfe4
commit
6055faff1b
7 files changed
+2420
-123
No files matched your search
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Ensambla un weights.rs desde varios certificados del banco de referencia (Laurha, la Pi 5).
|
||||
|
||||
python3 scripts/bench/ensamblar-pesos.py <weights.rs> <cert-antiguo.rs> ... <cert-vigente.rs>
|
||||
python3 scripts/bench/ensamblar-pesos.py --comprobar <weights.rs> <certs...> # 1 si no coincide
|
||||
|
||||
Por qué existe: «El máximo de 5 de un día no es el de otro» (Laurha, 29-oct). Entre dos
|
||||
certificados del mismo código, el base weight de un mismo extrinsic se separa hasta un 22 %. Si se
|
||||
cobra sólo el último certificado, se cobra de menos lo que otro día midió más alto sobre el MISMO
|
||||
código. Si se mezclan certificados de código distinto, se cobra lo que no corre.
|
||||
|
||||
La regla, función a función (en los dos impl, `SubstrateWeight<T>` y `()`):
|
||||
- El ÚLTIMO certificado de la lista es el del código que corre. Su bloque es la referencia: sus
|
||||
lecturas, escrituras, proof y lista de storage son las que se cobran.
|
||||
- Entran todos los certificados cuyo bloque tiene el MISMO esqueleto que la referencia: el cuerpo
|
||||
sin números ni comentarios numéricos. Un certificado de código anterior que lea otra cosa no entra.
|
||||
- Cada `Weight::from_parts(a, b)` cobra el máximo de los que entran, coeficiente a coeficiente.
|
||||
- Se niega si el esqueleto de la referencia no es el que ya tiene el weights.rs (el código cambió y
|
||||
no hay certificado de él) o si una función del weights.rs no está en la referencia.
|
||||
|
||||
Sólo toca los bloques de las funciones. La cabecera, el trait y la guarda de proof_size se quedan
|
||||
como están: la cabecera la escribe quien ensambla, y debe nombrar los certificados y sus shas.
|
||||
"""
|
||||
import hashlib, os, re, sys
|
||||
|
||||
IMPLS = ("impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {", "impl WeightInfo for () {")
|
||||
FN = re.compile(r"((?:\t//[^\n]*\n)*)\tfn (\w+)\(\) -> Weight \{\n.*?\n\t\}\n", re.S)
|
||||
PARTES = re.compile(r"from_parts\(([\d_]+), ([\d_]+)\)")
|
||||
|
||||
|
||||
def impl(texto, cabeza):
|
||||
a = texto.index(cabeza)
|
||||
b = texto.index("\n}\n", a) + 1
|
||||
return a, b
|
||||
|
||||
|
||||
def bloques(texto, cabeza):
|
||||
a, b = impl(texto, cabeza)
|
||||
return {m.group(2): m for m in FN.finditer(texto, a, b)}
|
||||
|
||||
|
||||
def esqueleto(bloque):
|
||||
cuerpo = bloque.split("\tfn ", 1)[1]
|
||||
cuerpo = re.sub(r"\t\t// [^\n]*\n", "", cuerpo)
|
||||
return PARTES.sub("from_parts(N, N)", cuerpo)
|
||||
|
||||
|
||||
def numeros(bloque):
|
||||
return [(int(a.replace("_", "")), int(b.replace("_", ""))) for a, b in PARTES.findall(bloque)]
|
||||
|
||||
|
||||
def ensamblar(destino, certs):
|
||||
texto = open(destino).read()
|
||||
leidos = [(os.path.basename(c).rsplit(".", 1)[0], open(c).read()) for c in certs]
|
||||
for cabeza in IMPLS:
|
||||
actuales = bloques(texto, cabeza)
|
||||
ref = bloques(leidos[-1][1], cabeza)
|
||||
otros = [(et, bloques(t, cabeza)) for et, t in leidos]
|
||||
nuevos = {}
|
||||
for nombre, m in actuales.items():
|
||||
if nombre not in ref:
|
||||
sys.exit(f"{nombre}: no está en el certificado vigente ({leidos[-1][0]})")
|
||||
r = ref[nombre].group(0)
|
||||
if esqueleto(r) != esqueleto(m.group(0)):
|
||||
sys.exit(f"{nombre}: el certificado vigente no mide el código del weights.rs")
|
||||
entran = [(et, b[nombre].group(0)) for et, b in otros
|
||||
if nombre in b and esqueleto(b[nombre].group(0)) == esqueleto(r)]
|
||||
maximos = [tuple(max(v) for v in zip(*col)) for col in zip(*[numeros(b) for _, b in entran])]
|
||||
it = iter(maximos)
|
||||
bloque = PARTES.sub(lambda _m: "from_parts({:_}, {:_})".format(*next(it)), r)
|
||||
etiquetas = ", ".join(et for et, _ in entran)
|
||||
bloque = re.sub(r"\t\t// Tiempo minimo de ejecucion:[^\n]*\n",
|
||||
f"\t\t// Máximo por coeficiente de: {etiquetas}.\n", bloque)
|
||||
nuevos[nombre] = bloque
|
||||
a, b = impl(texto, cabeza)
|
||||
seccion = FN.sub(lambda mm: nuevos[mm.group(2)], texto[a:b])
|
||||
texto = texto[:a] + seccion + texto[b:]
|
||||
return texto
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = sys.argv[1:]
|
||||
comprobar = bool(args) and args[0] == "--comprobar"
|
||||
if comprobar:
|
||||
args = args[1:]
|
||||
if len(args) < 2:
|
||||
sys.exit(__doc__)
|
||||
destino, certs = args[0], args[1:]
|
||||
nuevo = ensamblar(destino, certs)
|
||||
for c in certs:
|
||||
print(f" {hashlib.sha256(open(c, 'rb').read()).hexdigest()[:16]} {c}")
|
||||
if comprobar:
|
||||
igual = nuevo == open(destino).read()
|
||||
print("weights.rs coincide con el ensamblado" if igual else "weights.rs NO coincide con el ensamblado")
|
||||
sys.exit(0 if igual else 1)
|
||||
open(destino, "w").write(nuevo)
|
||||
print(f"ensamblado {destino} desde {len(certs)} certificados")
|
||||
Reference in new issue
Block a user