From c5a54fd45b261287cfd6f9fb6961b88e1152adc3 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 14 Dec 2023 16:25:07 +0100 Subject: [PATCH 1/7] remove private class field from Field --- src/lib/field.ts | 96 ++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/lib/field.ts b/src/lib/field.ts index 226689979f..9c33016624 100644 --- a/src/lib/field.ts +++ b/src/lib/field.ts @@ -156,7 +156,7 @@ class Field { * Coerce anything "field-like" (bigint, number, string, and {@link Field}) to a Field. */ constructor(x: bigint | number | string | Field | FieldVar | FieldConst) { - if (Field.#isField(x)) { + if (x instanceof Field) { this.value = x.value; return; } @@ -176,21 +176,9 @@ class Field { } // helpers - static #isField( - x: bigint | number | string | Field | FieldVar | FieldConst - ): x is Field { - return x instanceof Field; - } - static #toConst(x: bigint | number | string | ConstantField): FieldConst { - if (Field.#isField(x)) return x.value[1]; - return FieldConst.fromBigint(Fp(x)); - } - static #toVar(x: bigint | number | string | Field): FieldVar { - if (Field.#isField(x)) return x.value; - return FieldVar.constant(Fp(x)); - } + static from(x: bigint | number | string | Field): Field { - if (Field.#isField(x)) return x; + if (x instanceof Field) return x; return new Field(x); } @@ -216,10 +204,6 @@ class Field { return this.value[0] === FieldType.Constant; } - #toConstant(name: string): ConstantField { - return toConstantField(this, name, 'x', 'field element'); - } - /** * Create a {@link Field} element equivalent to this {@link Field} element's value, * but is a constant. @@ -234,7 +218,7 @@ class Field { * @return A constant {@link Field} element equivalent to this {@link Field} element. */ toConstant(): ConstantField { - return this.#toConstant('toConstant'); + return toConstant(this, 'toConstant'); } /** @@ -251,7 +235,7 @@ class Field { * @return A bigint equivalent to the bigint representation of the Field. */ toBigInt() { - let x = this.#toConstant('toBigInt'); + let x = toConstant(this, 'toBigInt'); return FieldConst.toBigint(x.value[1]); } @@ -269,7 +253,7 @@ class Field { * @return A string equivalent to the string representation of the Field. */ toString() { - return this.#toConstant('toString').toBigInt().toString(); + return toConstant(this, 'toString').toBigInt().toString(); } /** @@ -290,7 +274,7 @@ class Field { } return; } - Snarky.field.assertEqual(this.value, Field.#toVar(y)); + Snarky.field.assertEqual(this.value, toFieldVar(y)); } catch (err) { throw withMessage(err, message); } @@ -329,7 +313,7 @@ class Field { return new Field(Fp.add(this.toBigInt(), toFp(y))); } // return new AST node Add(x, y) - let z = Snarky.field.add(this.value, Field.#toVar(y)); + let z = Snarky.field.add(this.value, toFieldVar(y)); return new Field(z); } @@ -456,7 +440,7 @@ class Field { } // if one of the factors is constant, return Scale AST node if (isConstant(y)) { - let z = Snarky.field.scale(Field.#toConst(y), this.value); + let z = Snarky.field.scale(toFieldConst(y), this.value); return new Field(z); } if (this.isConstant()) { @@ -664,24 +648,6 @@ class Field { return new Field(xMinusY).isZero(); } - // internal base method for all comparisons - #compare(y: FieldVar) { - // TODO: support all bit lengths - let maxLength = Fp.sizeInBits - 2; - asProver(() => { - let actualLength = Math.max( - this.toBigInt().toString(2).length, - new Field(y).toBigInt().toString(2).length - ); - if (actualLength > maxLength) - throw Error( - `Provable comparison functions can only be used on Fields of size <= ${maxLength} bits, got ${actualLength} bits.` - ); - }); - let [, less, lessOrEqual] = Snarky.field.compare(maxLength, this.value, y); - return { less: new Bool(less), lessOrEqual: new Bool(lessOrEqual) }; - } - /** * Check if this {@link Field} is less than another "field-like" value. * Returns a {@link Bool}, which is a provable type and can be used prove to the validity of this statement. @@ -709,7 +675,7 @@ class Field { if (this.isConstant() && isConstant(y)) { return new Bool(this.toBigInt() < toFp(y)); } - return this.#compare(Field.#toVar(y)).less; + return compare(this, toFieldVar(y)).less; } /** @@ -739,7 +705,7 @@ class Field { if (this.isConstant() && isConstant(y)) { return new Bool(this.toBigInt() <= toFp(y)); } - return this.#compare(Field.#toVar(y)).lessOrEqual; + return compare(this, toFieldVar(y)).lessOrEqual; } /** @@ -817,7 +783,7 @@ class Field { } return; } - let { less } = this.#compare(Field.#toVar(y)); + let { less } = compare(this, toFieldVar(y)); less.assertTrue(); } catch (err) { throw withMessage(err, message); @@ -845,7 +811,7 @@ class Field { } return; } - let { lessOrEqual } = this.#compare(Field.#toVar(y)); + let { lessOrEqual } = compare(this, toFieldVar(y)); lessOrEqual.assertTrue(); } catch (err) { throw withMessage(err, message); @@ -1165,7 +1131,7 @@ class Field { * @return A string equivalent to the JSON representation of the {@link Field}. */ toJSON() { - return this.#toConstant('toJSON').toString(); + return toConstant(this, 'toJSON').toString(); } /** @@ -1279,6 +1245,8 @@ const FieldBinable = defineBinable({ }, }); +// internal helper functions + function isField(x: unknown): x is Field { return x instanceof Field; } @@ -1301,12 +1269,40 @@ function toFp(x: bigint | number | string | Field): Fp { return (x as Field).toBigInt(); } +function toFieldConst(x: bigint | number | string | ConstantField): FieldConst { + if (x instanceof Field) return x.value[1]; + return FieldConst.fromBigint(Fp(x)); +} + +function toFieldVar(x: bigint | number | string | Field): FieldVar { + if (x instanceof Field) return x.value; + return FieldVar.constant(Fp(x)); +} + function withMessage(error: unknown, message?: string) { if (message === undefined || !(error instanceof Error)) return error; error.message = `${message}\n${error.message}`; return error; } +// internal base method for all comparisons +function compare(x: Field, y: FieldVar) { + // TODO: support all bit lengths + let maxLength = Fp.sizeInBits - 2; + asProver(() => { + let actualLength = Math.max( + x.toBigInt().toString(2).length, + new Field(y).toBigInt().toString(2).length + ); + if (actualLength > maxLength) + throw Error( + `Provable comparison functions can only be used on Fields of size <= ${maxLength} bits, got ${actualLength} bits.` + ); + }); + let [, less, lessOrEqual] = Snarky.field.compare(maxLength, x.value, y); + return { less: new Bool(less), lessOrEqual: new Bool(lessOrEqual) }; +} + function checkBitLength( name: string, length: number, @@ -1320,6 +1316,10 @@ function checkBitLength( throw Error(`${name}: bit length must be non-negative, got ${length}`); } +function toConstant(x: Field, name: string): ConstantField { + return toConstantField(x, name, 'x', 'field element'); +} + function toConstantField( x: Field, methodName: string, From bce7914ca64b7badd654e14797fc5b2debd6af9d Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 14 Dec 2023 16:27:28 +0100 Subject: [PATCH 2/7] remove unnecessary helper functions --- src/lib/bool.ts | 6 +----- src/lib/field.ts | 5 ----- src/lib/group.ts | 6 +++--- src/lib/provable.ts | 8 +------- 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/lib/bool.ts b/src/lib/bool.ts index 9d7fee9e4d..85d4fab607 100644 --- a/src/lib/bool.ts +++ b/src/lib/bool.ts @@ -11,7 +11,7 @@ import { defineBinable } from '../bindings/lib/binable.js'; import { NonNegativeInteger } from '../bindings/crypto/non-negative.js'; import { asProver } from './provable-context.js'; -export { BoolVar, Bool, isBool }; +export { BoolVar, Bool }; // same representation, but use a different name to communicate intent / constraints type BoolVar = FieldVar; @@ -370,10 +370,6 @@ function isConstant(x: boolean | Bool): x is boolean | ConstantBool { return x.isConstant(); } -function isBool(x: unknown) { - return x instanceof Bool; -} - function toBoolean(x: boolean | Bool): boolean { if (typeof x === 'boolean') { return x; diff --git a/src/lib/field.ts b/src/lib/field.ts index 9c33016624..891390619d 100644 --- a/src/lib/field.ts +++ b/src/lib/field.ts @@ -17,7 +17,6 @@ export { ConstantField, VarField, VarFieldVar, - isField, withMessage, readVarMessage, toConstantField, @@ -1247,10 +1246,6 @@ const FieldBinable = defineBinable({ // internal helper functions -function isField(x: unknown): x is Field { - return x instanceof Field; -} - function isConstant( x: bigint | number | string | Field ): x is bigint | number | string | ConstantField { diff --git a/src/lib/group.ts b/src/lib/group.ts index 6178032df6..4cd6d9e147 100644 --- a/src/lib/group.ts +++ b/src/lib/group.ts @@ -1,4 +1,4 @@ -import { Field, FieldVar, isField } from './field.js'; +import { Field, FieldVar } from './field.js'; import { Scalar } from './scalar.js'; import { Snarky } from '../snarky.js'; import { Field as Fp } from '../provable/field-bigint.js'; @@ -48,8 +48,8 @@ class Group { x: FieldVar | Field | number | string | bigint; y: FieldVar | Field | number | string | bigint; }) { - this.x = isField(x) ? x : new Field(x); - this.y = isField(y) ? y : new Field(y); + this.x = x instanceof Field ? x : new Field(x); + this.y = y instanceof Field ? y : new Field(y); if (this.#isConstant()) { // we also check the zero element (0, 0) here diff --git a/src/lib/provable.ts b/src/lib/provable.ts index 534818f16f..8094bcf89e 100644 --- a/src/lib/provable.ts +++ b/src/lib/provable.ts @@ -13,7 +13,6 @@ import { InferProvable, InferredProvable, } from '../bindings/lib/provable-snarky.js'; -import { isField } from './field.js'; import { inCheckedComputation, inProver, @@ -23,7 +22,6 @@ import { runUnchecked, constraintSystem, } from './provable-context.js'; -import { isBool } from './bool.js'; // external API export { Provable }; @@ -345,11 +343,7 @@ function ifImplicit(condition: Bool, x: T, y: T): T { ); // TODO remove second condition once we have consolidated field class back into one // if (type !== y.constructor) { - if ( - type !== y.constructor && - !(isField(x) && isField(y)) && - !(isBool(x) && isBool(y)) - ) { + if (type !== y.constructor) { throw Error( 'Provable.if: Mismatched argument types. Try using an explicit type argument:\n' + `Provable.if(bool, MyType, x, y)` From 4ba40a12695c528cf0a265853a845b3f37f717db Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 14 Dec 2023 16:30:39 +0100 Subject: [PATCH 3/7] remove private class fields from Bool --- src/lib/bool.ts | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/lib/bool.ts b/src/lib/bool.ts index 85d4fab607..8957e89d53 100644 --- a/src/lib/bool.ts +++ b/src/lib/bool.ts @@ -34,7 +34,7 @@ class Bool { value: BoolVar; constructor(x: boolean | Bool | BoolVar) { - if (Bool.#isBool(x)) { + if (x instanceof Bool) { this.value = x.value; return; } @@ -75,7 +75,7 @@ class Bool { if (this.isConstant() && isConstant(y)) { return new Bool(this.toBoolean() && toBoolean(y)); } - return new Bool(Snarky.bool.and(this.value, Bool.#toVar(y))); + return new Bool(Snarky.bool.and(this.value, toFieldVar(y))); } /** @@ -87,7 +87,7 @@ class Bool { if (this.isConstant() && isConstant(y)) { return new Bool(this.toBoolean() || toBoolean(y)); } - return new Bool(Snarky.bool.or(this.value, Bool.#toVar(y))); + return new Bool(Snarky.bool.or(this.value, toFieldVar(y))); } /** @@ -102,7 +102,7 @@ class Bool { } return; } - Snarky.bool.assertEqual(this.value, Bool.#toVar(y)); + Snarky.bool.assertEqual(this.value, toFieldVar(y)); } catch (err) { throw withMessage(err, message); } @@ -144,7 +144,7 @@ class Bool { if (this.isConstant() && isConstant(y)) { return new Bool(this.toBoolean() === toBoolean(y)); } - return new Bool(Snarky.bool.equals(this.value, Bool.#toVar(y))); + return new Bool(Snarky.bool.equals(this.value, toFieldVar(y))); } /** @@ -194,14 +194,14 @@ class Bool { } static toField(x: Bool | boolean): Field { - return new Field(Bool.#toVar(x)); + return new Field(toFieldVar(x)); } /** * Boolean negation. */ static not(x: Bool | boolean): Bool { - if (Bool.#isBool(x)) { + if (x instanceof Bool) { return x.not(); } return new Bool(!x); @@ -211,7 +211,7 @@ class Bool { * Boolean AND operation. */ static and(x: Bool | boolean, y: Bool | boolean): Bool { - if (Bool.#isBool(x)) { + if (x instanceof Bool) { return x.and(y); } return new Bool(x).and(y); @@ -221,7 +221,7 @@ class Bool { * Boolean OR operation. */ static or(x: Bool | boolean, y: Bool | boolean): Bool { - if (Bool.#isBool(x)) { + if (x instanceof Bool) { return x.or(y); } return new Bool(x).or(y); @@ -231,7 +231,7 @@ class Bool { * Asserts if both {@link Bool} are equal. */ static assertEqual(x: Bool, y: Bool | boolean): void { - if (Bool.#isBool(x)) { + if (x instanceof Bool) { x.assertEquals(y); return; } @@ -242,7 +242,7 @@ class Bool { * Checks two {@link Bool} for equality. */ static equal(x: Bool | boolean, y: Bool | boolean): Bool { - if (Bool.#isBool(x)) { + if (x instanceof Bool) { return x.equals(y); } return new Bool(x).equals(y); @@ -342,15 +342,6 @@ class Bool { return new Bool(x.value); }, }; - - static #isBool(x: boolean | Bool | BoolVar): x is Bool { - return x instanceof Bool; - } - - static #toVar(x: boolean | Bool): BoolVar { - if (Bool.#isBool(x)) return x.value; - return FieldVar.constant(B(x)); - } } const BoolBinable = defineBinable({ @@ -362,6 +353,8 @@ const BoolBinable = defineBinable({ }, }); +// internal helper functions + function isConstant(x: boolean | Bool): x is boolean | ConstantBool { if (typeof x === 'boolean') { return true; @@ -377,6 +370,11 @@ function toBoolean(x: boolean | Bool): boolean { return x.toBoolean(); } +function toFieldVar(x: boolean | Bool): BoolVar { + if (x instanceof Bool) return x.value; + return FieldVar.constant(B(x)); +} + // TODO: This is duplicated function withMessage(error: unknown, message?: string) { if (message === undefined || !(error instanceof Error)) return error; From 4f75418988263124f5f854311f1a65dcad7e6f1f Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 14 Dec 2023 16:37:45 +0100 Subject: [PATCH 4/7] remove private class fields from Group --- src/lib/group.ts | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/lib/group.ts b/src/lib/group.ts index 4cd6d9e147..67b021097e 100644 --- a/src/lib/group.ts +++ b/src/lib/group.ts @@ -51,7 +51,7 @@ class Group { this.x = x instanceof Field ? x : new Field(x); this.y = y instanceof Field ? y : new Field(y); - if (this.#isConstant()) { + if (isConstant(this)) { // we also check the zero element (0, 0) here if (this.x.equals(0).and(this.y.equals(0)).toBoolean()) return; @@ -72,31 +72,6 @@ class Group { } } - // helpers - static #fromAffine({ x, y, infinity }: GroupAffine) { - return infinity ? Group.zero : new Group({ x, y }); - } - - static #fromProjective({ x, y, z }: { x: bigint; y: bigint; z: bigint }) { - return this.#fromAffine(Pallas.toAffine({ x, y, z })); - } - - #toTuple(): [0, FieldVar, FieldVar] { - return [0, this.x.value, this.y.value]; - } - - #isConstant() { - return this.x.isConstant() && this.y.isConstant(); - } - - #toProjective() { - return Pallas.fromAffine({ - x: this.x.toBigInt(), - y: this.y.toBigInt(), - infinity: false, - }); - } - /** * Checks if this element is the `zero` element `{x: 0, y: 0}`. */ @@ -114,15 +89,15 @@ class Group { * ``` */ add(g: Group) { - if (this.#isConstant() && g.#isConstant()) { + if (isConstant(this) && isConstant(g)) { // we check if either operand is zero, because adding zero to g just results in g (and vise versa) if (this.isZero().toBoolean()) { return g; } else if (g.isZero().toBoolean()) { return this; } else { - let g_proj = Pallas.add(this.#toProjective(), g.#toProjective()); - return Group.#fromProjective(g_proj); + let g_proj = Pallas.add(toProjective(this), toProjective(g)); + return fromProjective(g_proj); } } else { const { x: x1, y: y1 } = this; @@ -163,9 +138,9 @@ class Group { }); let [, x, y] = Snarky.gates.ecAdd( - Group.from(x1.seal(), y1.seal()).#toTuple(), - Group.from(x2.seal(), y2.seal()).#toTuple(), - Group.from(x3, y3).#toTuple(), + toTuple(Group.from(x1.seal(), y1.seal())), + toTuple(Group.from(x2.seal(), y2.seal())), + toTuple(Group.from(x3, y3)), inf.toField().value, same_x.value, s.value, @@ -216,13 +191,13 @@ class Group { scale(s: Scalar | number | bigint) { let scalar = Scalar.from(s); - if (this.#isConstant() && scalar.isConstant()) { - let g_proj = Pallas.scale(this.#toProjective(), scalar.toBigInt()); - return Group.#fromProjective(g_proj); + if (isConstant(this) && scalar.isConstant()) { + let g_proj = Pallas.scale(toProjective(this), scalar.toBigInt()); + return fromProjective(g_proj); } else { let [, ...bits] = scalar.value; bits.reverse(); - let [, x, y] = Snarky.group.scale(this.#toTuple(), [0, ...bits]); + let [, x, y] = Snarky.group.scale(toTuple(this), [0, ...bits]); return new Group({ x, y }); } } @@ -448,3 +423,29 @@ class Group { } } } + +// internal helpers + +function isConstant(g: Group) { + return g.x.isConstant() && g.y.isConstant(); +} + +function toTuple(g: Group): [0, FieldVar, FieldVar] { + return [0, g.x.value, g.y.value]; +} + +function toProjective(g: Group) { + return Pallas.fromAffine({ + x: g.x.toBigInt(), + y: g.y.toBigInt(), + infinity: false, + }); +} + +function fromProjective({ x, y, z }: { x: bigint; y: bigint; z: bigint }) { + return fromAffine(Pallas.toAffine({ x, y, z })); +} + +function fromAffine({ x, y, infinity }: GroupAffine) { + return infinity ? Group.zero : new Group({ x, y }); +} From 9690a5b42eca15e32081ba539d35652917198c80 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 14 Dec 2023 16:44:08 +0100 Subject: [PATCH 5/7] remove private class Fields from Scalar --- src/lib/scalar.ts | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/lib/scalar.ts b/src/lib/scalar.ts index 176478947f..d54f20c209 100644 --- a/src/lib/scalar.ts +++ b/src/lib/scalar.ts @@ -88,7 +88,7 @@ class Scalar { * Convert this {@link Scalar} into a bigint */ toBigInt() { - return this.#assertConstant('toBigInt'); + return assertConstant(this, 'toBigInt'); } // TODO: fix this API. we should represent "shifted status" internally and use @@ -112,17 +112,13 @@ class Scalar { // operations on constant scalars - #assertConstant(name: string) { - return constantScalarToBigint(this, `Scalar.${name}`); - } - /** * Negate a scalar field element. * * **Warning**: This method is not available for provable code. */ neg() { - let x = this.#assertConstant('neg'); + let x = assertConstant(this, 'neg'); let z = Fq.negate(x); return Scalar.from(z); } @@ -133,8 +129,8 @@ class Scalar { * **Warning**: This method is not available for provable code. */ add(y: Scalar) { - let x = this.#assertConstant('add'); - let y0 = y.#assertConstant('add'); + let x = assertConstant(this, 'add'); + let y0 = assertConstant(y, 'add'); let z = Fq.add(x, y0); return Scalar.from(z); } @@ -145,8 +141,8 @@ class Scalar { * **Warning**: This method is not available for provable code. */ sub(y: Scalar) { - let x = this.#assertConstant('sub'); - let y0 = y.#assertConstant('sub'); + let x = assertConstant(this, 'sub'); + let y0 = assertConstant(y, 'sub'); let z = Fq.sub(x, y0); return Scalar.from(z); } @@ -157,8 +153,8 @@ class Scalar { * **Warning**: This method is not available for provable code. */ mul(y: Scalar) { - let x = this.#assertConstant('mul'); - let y0 = y.#assertConstant('mul'); + let x = assertConstant(this, 'mul'); + let y0 = assertConstant(y, 'mul'); let z = Fq.mul(x, y0); return Scalar.from(z); } @@ -170,8 +166,8 @@ class Scalar { * **Warning**: This method is not available for provable code. */ div(y: Scalar) { - let x = this.#assertConstant('div'); - let y0 = y.#assertConstant('div'); + let x = assertConstant(this, 'div'); + let y0 = assertConstant(y, 'div'); let z = Fq.div(x, y0); if (z === undefined) throw Error('Scalar.div(): Division by zero'); return Scalar.from(z); @@ -179,11 +175,11 @@ class Scalar { // TODO don't leak 'shifting' to the user and remove these methods shift() { - let x = this.#assertConstant('shift'); + let x = assertConstant(this, 'shift'); return Scalar.from(shift(x)); } unshift() { - let x = this.#assertConstant('unshift'); + let x = assertConstant(this, 'unshift'); return Scalar.from(unshift(x)); } @@ -196,7 +192,7 @@ class Scalar { * is needed to represent all Scalars. However, for a random Scalar, the high bit will be `false` with overwhelming probability. */ toFieldsCompressed(): { field: Field; highBit: Bool } { - let s = this.#assertConstant('toFieldsCompressed'); + let s = assertConstant(this, 'toFieldsCompressed'); let lowBitSize = BigInt(Fq.sizeInBits - 1); let lowBitMask = (1n << lowBitSize) - 1n; return { @@ -292,7 +288,7 @@ class Scalar { * This operation does _not_ affect the circuit and can't be used to prove anything about the string representation of the Scalar. */ static toJSON(x: Scalar) { - let s = x.#assertConstant('toJSON'); + let s = assertConstant(x, 'toJSON'); return s.toString(); } @@ -312,6 +308,12 @@ class Scalar { } } +// internal helpers + +function assertConstant(x: Scalar, name: string) { + return constantScalarToBigint(x, `Scalar.${name}`); +} + function toConstantScalar([, ...bits]: MlArray): Fq | undefined { if (bits.length !== Fq.sizeInBits) throw Error( From 96c756a1f95ebe1f932954db51f01285065fd178 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 14 Dec 2023 16:54:29 +0100 Subject: [PATCH 6/7] remove private class fields from SmartContract --- src/lib/zkapp.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/zkapp.ts b/src/lib/zkapp.ts index 6986966a3d..77387d367f 100644 --- a/src/lib/zkapp.ts +++ b/src/lib/zkapp.ts @@ -601,7 +601,7 @@ class SmartContract { address: PublicKey; tokenId: Field; - #executionState: ExecutionState | undefined; + private _executionState: ExecutionState | undefined; // here we store various metadata associated with a SmartContract subclass. // by initializing all of these to `undefined`, we ensure that @@ -758,8 +758,8 @@ class SmartContract { else this.init(); let initUpdate = this.self; // switch back to the deploy account update so the user can make modifications to it - this.#executionState = { - transactionId: this.#executionState!.transactionId, + this._executionState = { + transactionId: this._executionState!.transactionId, accountUpdate, }; // check if the entire state was overwritten, show a warning if not @@ -853,10 +853,10 @@ super.init(); // it won't create new updates and add them to a transaction implicitly if (inSmartContract && inSmartContract.this === this) { let accountUpdate = inSmartContract.selfUpdate; - this.#executionState = { accountUpdate, transactionId }; + this._executionState = { accountUpdate, transactionId }; return accountUpdate; } - let executionState = this.#executionState; + let executionState = this._executionState; if ( executionState !== undefined && executionState.transactionId === transactionId @@ -866,7 +866,7 @@ super.init(); // if in a transaction, but outside a @method call, we implicitly create an account update // which is stable during the current transaction -- as long as it doesn't get overridden by a method call let accountUpdate = selfAccountUpdate(this); - this.#executionState = { transactionId, accountUpdate }; + this._executionState = { transactionId, accountUpdate }; return accountUpdate; } // same as this.self, but explicitly creates a _new_ account update @@ -877,11 +877,11 @@ super.init(); let inTransaction = Mina.currentTransaction.has(); let transactionId = inTransaction ? Mina.currentTransaction.id() : NaN; let accountUpdate = selfAccountUpdate(this); - this.#executionState = { transactionId, accountUpdate }; + this._executionState = { transactionId, accountUpdate }; return accountUpdate; } - #_senderState: { sender: PublicKey; transactionId: number }; + private _senderState: { sender: PublicKey; transactionId: number }; /** * The public key of the current transaction's sender account. @@ -900,11 +900,11 @@ super.init(); ); } let transactionId = Mina.currentTransaction.id(); - if (this.#_senderState?.transactionId === transactionId) { - return this.#_senderState.sender; + if (this._senderState?.transactionId === transactionId) { + return this._senderState.sender; } else { let sender = Provable.witness(PublicKey, () => Mina.sender()); - this.#_senderState = { transactionId, sender }; + this._senderState = { transactionId, sender }; return sender; } } @@ -1195,7 +1195,7 @@ super.init(); publicInput, ...args ); - accountUpdate = instance.#executionState!.accountUpdate; + accountUpdate = instance._executionState!.accountUpdate; return result; } ); From c40e3f1a661f696c4f1f35515696f3e82a2ad99b Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 14 Dec 2023 18:00:20 +0100 Subject: [PATCH 7/7] Revert "remove private class fields from SmartContract" This reverts commit 96c756a1f95ebe1f932954db51f01285065fd178. --- src/lib/zkapp.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/zkapp.ts b/src/lib/zkapp.ts index 77387d367f..6986966a3d 100644 --- a/src/lib/zkapp.ts +++ b/src/lib/zkapp.ts @@ -601,7 +601,7 @@ class SmartContract { address: PublicKey; tokenId: Field; - private _executionState: ExecutionState | undefined; + #executionState: ExecutionState | undefined; // here we store various metadata associated with a SmartContract subclass. // by initializing all of these to `undefined`, we ensure that @@ -758,8 +758,8 @@ class SmartContract { else this.init(); let initUpdate = this.self; // switch back to the deploy account update so the user can make modifications to it - this._executionState = { - transactionId: this._executionState!.transactionId, + this.#executionState = { + transactionId: this.#executionState!.transactionId, accountUpdate, }; // check if the entire state was overwritten, show a warning if not @@ -853,10 +853,10 @@ super.init(); // it won't create new updates and add them to a transaction implicitly if (inSmartContract && inSmartContract.this === this) { let accountUpdate = inSmartContract.selfUpdate; - this._executionState = { accountUpdate, transactionId }; + this.#executionState = { accountUpdate, transactionId }; return accountUpdate; } - let executionState = this._executionState; + let executionState = this.#executionState; if ( executionState !== undefined && executionState.transactionId === transactionId @@ -866,7 +866,7 @@ super.init(); // if in a transaction, but outside a @method call, we implicitly create an account update // which is stable during the current transaction -- as long as it doesn't get overridden by a method call let accountUpdate = selfAccountUpdate(this); - this._executionState = { transactionId, accountUpdate }; + this.#executionState = { transactionId, accountUpdate }; return accountUpdate; } // same as this.self, but explicitly creates a _new_ account update @@ -877,11 +877,11 @@ super.init(); let inTransaction = Mina.currentTransaction.has(); let transactionId = inTransaction ? Mina.currentTransaction.id() : NaN; let accountUpdate = selfAccountUpdate(this); - this._executionState = { transactionId, accountUpdate }; + this.#executionState = { transactionId, accountUpdate }; return accountUpdate; } - private _senderState: { sender: PublicKey; transactionId: number }; + #_senderState: { sender: PublicKey; transactionId: number }; /** * The public key of the current transaction's sender account. @@ -900,11 +900,11 @@ super.init(); ); } let transactionId = Mina.currentTransaction.id(); - if (this._senderState?.transactionId === transactionId) { - return this._senderState.sender; + if (this.#_senderState?.transactionId === transactionId) { + return this.#_senderState.sender; } else { let sender = Provable.witness(PublicKey, () => Mina.sender()); - this._senderState = { transactionId, sender }; + this.#_senderState = { transactionId, sender }; return sender; } } @@ -1195,7 +1195,7 @@ super.init(); publicInput, ...args ); - accountUpdate = instance._executionState!.accountUpdate; + accountUpdate = instance.#executionState!.accountUpdate; return result; } );