Skip to content

Commit 76fd709

Browse files
authored
Merge pull request #2134 from o1-labs/v2/fix-au-tests
Fix V2 `AccountUpdate` conversion tests
2 parents 47eff1c + 128d330 commit 76fd709

File tree

6 files changed

+55
-43
lines changed

6 files changed

+55
-43
lines changed

CHANGELOG.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1717

1818
## [Unreleased](https://github.com/o1-labs/o1js/compare/6ff7f8470a...HEAD)
1919

20+
### Fixed
21+
22+
- Correct handling of actions and events lists as well as internal `AccountUpdate` consistency tests for the new V2 API. https://github.com/o1-labs/o1js/pull/2134
23+
2024
### Added
2125

2226
- [PR !2076](https://github.com/o1-labs/o1js/pull/2076)
23-
- o1js-bindings is no longer a submodule (same directory structure)
24-
- compiled artifacts are now gitignored
25-
- `npm run build:bindings-download` downloads compiled artifacts from github
26-
- `npm run build:bindings-remote` triggers a github workflow to build the compiled artifacts then downloads them
27+
- o1js-bindings is no longer a submodule (same directory structure)
28+
- compiled artifacts are now gitignored
29+
- `npm run build:bindings-download` downloads compiled artifacts from github
30+
- `npm run build:bindings-remote` triggers a github workflow to build the compiled artifacts then downloads them
2731

2832
### Changed
2933

src/examples/v2/mina-program.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const TestProgram = V2.MinaProgram({
3939
x: V2.Update.from(value, Field(0)) as never,
4040
address: V2.Update.from(env.accountId.publicKey, PublicKey.empty()) as never,
4141
},
42+
pushActions: [
43+
[Field(1), Field(2)],
44+
[Field(3), Field(4)],
45+
],
4246
};
4347
},
4448
},

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ namespace Experimental {
156156
Action,
157157
MethodPrivateInputs extends { [key: string]: V2_.ProvableTuple }
158158
> = V2_.MinaProgram<State, Event, Action, MethodPrivateInputs>;
159+
export type DynamicProvable<P> = V2_.DynamicProvable<P>;
159160
}
160161

161162
export let memoizeWitness = Experimental_.memoizeWitness;

src/lib/mina/v2/account-update.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ import { NetworkId } from '../../../mina-signer/src/types.js';
3636
import { Struct } from '../../provable/types/struct.js';
3737
import { VerificationKey } from '../../../lib/proof-system/verification-key.js';
3838

39-
// TODO: make private abstractions over many fields (eg new apis for Update and Constraint.*)
40-
// TODO: replay checks
4139
// TODO: make private abstractions over many fields (eg new apis for Update and Constraint.*)
4240
// TODO: replay checks
4341
export {
@@ -50,6 +48,9 @@ export {
5048
ContextFreeAccountUpdate,
5149
DynamicProvable,
5250
AccountUpdateCommitment,
51+
CommittedList,
52+
EventsHashConfig,
53+
ActionsHashConfig,
5354
};
5455
class AccountUpdateCommitment extends Struct({
5556
accountUpdateCommitment: Field,
@@ -79,7 +80,8 @@ const GenericData: DynamicProvable<Field[]> = {
7980
},
8081

8182
fromFieldsDynamic(fields: Field[], aux: any[]): { value: Field[]; fieldsConsumed: number } {
82-
const [len] = aux;
83+
const [_len] = aux;
84+
let len = _len ?? fields.length;
8385
return { value: fields.slice(0, len), fieldsConsumed: len };
8486
},
8587
};
@@ -185,7 +187,6 @@ class CommittedList<Item> {
185187
return result;
186188
});
187189
}
188-
189190
//hash = value.hash;
190191
}
191192

@@ -813,8 +814,8 @@ class AccountUpdate<
813814
return Bindings.Layout.AccountUpdateBody.toFields(x.toInternalRepr(0));
814815
}
815816

816-
static toAuxiliary(x?: AccountUpdate): any[] {
817-
return Bindings.Layout.AccountUpdateBody.toAuxiliary(x?.toInternalRepr(0));
817+
static toAuxiliary(x?: AccountUpdate, callDepth?: number): any[] {
818+
return Bindings.Layout.AccountUpdateBody.toAuxiliary(x?.toInternalRepr(callDepth ?? 0));
818819
}
819820

820821
static fromFields(fields: Field[], aux: any[]): AccountUpdate {
@@ -1011,9 +1012,10 @@ class Authorized<State extends StateLayout = 'GenericState', Event = Field[], Ac
10111012
}
10121013

10131014
static toAuxiliary<State extends StateLayout = 'GenericState', Event = Field[], Action = Field[]>(
1014-
x?: Authorized<State, Event, Action>
1015+
x?: Authorized<State, Event, Action>,
1016+
callDepth?: number
10151017
): any[] {
1016-
return Bindings.Layout.ZkappAccountUpdate.toAuxiliary(x?.toInternalRepr(0));
1018+
return Bindings.Layout.ZkappAccountUpdate.toAuxiliary(x?.toInternalRepr(callDepth ?? 0));
10171019
}
10181020

10191021
static fromFields(fields: Field[], aux: any[]): Authorized {

src/lib/mina/v2/account-update.unit-test.ts

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { VerificationKey } from '../../proof-system/verification-key.js';
99
import { Bool } from '../../provable/bool.js';
1010
import { Field } from '../../provable/field.js';
1111
import { UInt32, UInt64, Int64, Sign } from '../../provable/int.js';
12-
import { PublicKey, PrivateKey } from '../../provable/crypto/signature.js';
12+
import { PrivateKey } from '../../provable/crypto/signature.js';
1313
import {
1414
Actions as V1Actions,
1515
Events as V1Events,
@@ -24,6 +24,19 @@ import { jsLayout as layoutV1 } from '../../../bindings/mina-transaction/gen/v1/
2424
import { expect } from 'expect';
2525

2626
import { ZkappConstants } from '../v1/constants.js';
27+
import {
28+
testV1V2ClassEquivalence,
29+
testV1V2ValueEquivalence,
30+
testV2Encoding,
31+
} from './test/utils.js';
32+
import {
33+
Signature,
34+
signFieldElement,
35+
zkAppBodyPrefix,
36+
} from '../../../mina-signer/src/signature.js';
37+
38+
import { Types } from '../../../bindings/mina-transaction/v1/types.js';
39+
import { packToFields, hashWithPrefix } from '../../../lib/provable/crypto/poseidon.js';
2740

2841
function testHashEquality(v1: TypesV1.AccountUpdate, v2: Authorized) {
2942
expect(TypesV1.AccountUpdate.toInput(v1)).toEqual(v2.toInput());
@@ -425,54 +438,39 @@ const v2AccountUpdate: Authorized = new Authorized(
425438
{
426439
// TODO: the fact that all these extra type-annotation are required means we didn't encode this
427440
// type well for typescript's poor type inference
428-
//testV2Encoding<Authorized>(Authorized, v2AccountUpdate);
429-
/*
441+
testV2Encoding<Authorized>(Authorized, v2AccountUpdate);
442+
430443
testV1V2ClassEquivalence<number, TypesV1.AccountUpdate, Authorized>(
431444
V1AccountUpdate,
432445
Authorized,
433446
0
434447
);
435-
*/
436-
testHashEquality(V1AccountUpdate.empty(), Authorized.empty());
437448

438-
/*
449+
testHashEquality(V1AccountUpdate.empty(), Authorized.empty());
439450
testV1V2ValueEquivalence<number, TypesV1.AccountUpdate, Authorized>(
440451
V1AccountUpdate,
441452
Authorized,
442453
v1AccountUpdate,
443454
v2AccountUpdate,
444455
2
445456
);
446-
*/
457+
447458
testHashEquality(v1AccountUpdate, v2AccountUpdate);
448459
}
449460

450461
// signature test
451462
{
452-
const v2Update = v2AccountUpdate.toAccountUpdate();
453-
454-
const v2UpdateSigned = await v2Update.authorize({
455-
networkId: 'testnet',
456-
async getPrivateKey(pk: PublicKey): Promise<PrivateKey> {
457-
if (pk !== publicKey) throw new Error();
458-
return privateKey;
459-
},
460-
accountUpdateForestCommitment: BigInt(0),
461-
fullTransactionCommitment: BigInt(0),
462-
});
463-
464-
// TODO: We need to actually ensure the signatures match the old implementation, but the old
465-
// interface makes this test annoying to implement, so skipping for right now.
466-
console.log(`signature = ${JSON.stringify(v2UpdateSigned.authorization.signature)}`);
463+
let v1Hash = hashWithPrefix(
464+
zkAppBodyPrefix('testnet'),
465+
packToFields(Types.AccountUpdate.toInput(v1AccountUpdate))
466+
);
467+
let v1Signature = signFieldElement(v1Hash.toBigInt(), privateKey.toBigInt(), 'testnet');
467468

468-
/*
469-
// HACK
470-
const v1Update = {...v2AccountUpdate} as unknown as V1AccountUpdateImpl;
471-
Object.setPrototypeOf(v1Update, V1AccountUpdateImpl.prototype);
469+
const v2Update = v2AccountUpdate.toAccountUpdate();
470+
let v2Hash = v2Update.commit('testnet').accountUpdateCommitment.toBigInt();
471+
let v2Signature = signFieldElement(v2Hash, privateKey.toBigInt(), 'testnet');
472472

473-
expect(v2UpdateSigned.authorization.signature)
474-
.toEqual(v1Update.authorization.signature);
475-
*/
473+
expect(Signature.toBase58(v1Signature)).toEqual(Signature.toBase58(v2Signature));
476474
}
477475

478476
console.log('\n:)');

src/lib/mina/v2/test/utils.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export type V1Type<T> = ProvableTypeDef<T> & {
5757
export type V2Type<InternalReprArg, V1, V2 extends V2Value<any, V1>> = ProvableTypeDef<V2> & {
5858
fromInternalRepr(x: V1): V2;
5959
toJSON(x: V2, arg: InternalReprArg): any;
60+
toAuxiliary(x: V2, arg?: InternalReprArg): any;
6061
};
6162

6263
export interface V2Value<InternalReprArg, V1> {
@@ -111,13 +112,15 @@ export function testV1V2ValueEquivalence<
111112
expect(v2Value.toFields()).toEqual(V1Type.toFields(v1Value));
112113

113114
// auxiliary equality
114-
expect(V2Type.toAuxiliary(v2Value)).toEqual(V1Type.toAuxiliary(v1Value));
115+
expect(V2Type.toAuxiliary(v2Value, v2InternalReprArg)).toEqual(V1Type.toAuxiliary(v1Value));
115116

116117
// v1 -> v2 via fields
117118
expect(V2Type.fromFields(V1Type.toFields(v1Value), V1Type.toAuxiliary(v1Value))).toEqual(v2Value);
118119

119120
// v1 -> v2 via fields
120-
expect(V1Type.fromFields(V2Type.toFields(v2Value), V2Type.toAuxiliary(v2Value))).toEqual(v1Value);
121+
expect(
122+
V1Type.fromFields(V2Type.toFields(v2Value), V2Type.toAuxiliary(v2Value, v2InternalReprArg))
123+
).toEqual(v1Value);
121124

122125
// input equality
123126
expect(V1Type.toInput(v1Value)).toEqual(V2Type.toInput(v2Value));

0 commit comments

Comments
 (0)