o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
129 lines (105 loc) • 4.37 kB
text/typescript
import { mocks } from '../../../bindings/crypto/constants.js';
import { AccountUpdate, PrivateKey, Field, Bool, Mina, Int64, Types } from '../../../index.js';
import { Test } from '../../../bindings.js';
import { expect } from 'expect';
let mlTest = await Test();
let address = PrivateKey.random().toPublicKey();
function createAccountUpdate() {
let accountUpdate = AccountUpdate.default(address);
accountUpdate.body.balanceChange = Int64.from(1e9).neg();
return accountUpdate;
}
function createAccountUpdateWithMayUseToken(mayUseToken: AccountUpdate['body']['mayUseToken']) {
let accountUpdate = AccountUpdate.default(address);
accountUpdate.body.mayUseToken = mayUseToken;
return accountUpdate;
}
// can convert account update to fields consistently
{
let accountUpdate = createAccountUpdate();
// convert accountUpdate to fields in OCaml, going via AccountUpdate.of_json
let json = JSON.stringify(accountUpdate.toJSON().body);
let [, ...fields1_] = mlTest.fieldsFromJson.accountUpdate(json);
let fields1 = fields1_.map(Field);
// convert accountUpdate to fields in pure JS, leveraging generated code
let fields2 = Types.AccountUpdate.toFields(accountUpdate);
// this is useful console output in the case the test should fail
if (fields1.length !== fields2.length) {
console.log(`unequal length. expected ${fields1.length}, actual: ${fields2.length}`);
}
for (let i = 0; i < fields1.length; i++) {
if (fields1[i].toString() !== fields2[i].toString()) {
console.log('unequal at', i);
console.log(`expected: ${fields1[i]} actual: ${fields2[i]}`);
}
}
expect(fields1.length).toEqual(fields2.length);
expect(fields1.map(String)).toEqual(fields2.map(String));
expect(fields1).toEqual(fields2);
}
// can hash an account update
{
let accountUpdate = createAccountUpdate();
let hash = accountUpdate.hash();
// if we clone the accountUpdate, hash should be the same
let accountUpdate2 = AccountUpdate.clone(accountUpdate);
expect(accountUpdate2.hash()).toEqual(hash);
// if we change something on the cloned accountUpdate, the hash should become different
AccountUpdate.setValue(accountUpdate2.update.appState[0], Field(1));
expect(accountUpdate2.hash()).not.toEqual(hash);
}
// converts account update to a public input that's consistent with the ocaml implementation
{
let otherAddress = PrivateKey.random().toPublicKey();
let accountUpdate = AccountUpdate.create(address);
let otherUpdate = AccountUpdate.create(otherAddress);
accountUpdate.approve(otherUpdate);
let publicInput = accountUpdate.toPublicInput({
accountUpdates: [accountUpdate, otherUpdate],
});
// create transaction JSON with the same accountUpdate structure, for ocaml version
let tx = await Mina.transaction(async () => {
let accountUpdate = AccountUpdate.create(address);
accountUpdate.approve(AccountUpdate.create(otherAddress));
});
let publicInputOcaml = mlTest.hashFromJson.zkappPublicInput(tx.toJSON(), 0);
expect(publicInput).toEqual({
accountUpdate: Field(publicInputOcaml.accountUpdate),
calls: Field(publicInputOcaml.calls),
});
}
// creates the right empty sequence state
{
let accountUpdate = createAccountUpdate();
expect(accountUpdate.body.preconditions.account.actionState.value.toString()).toEqual(
'25079927036070901246064867767436987657692091363973573142121686150614948079097'
);
}
// creates the right empty vk hash
{
let accountUpdate = createAccountUpdate();
expect(accountUpdate.body.authorizationKind.verificationKeyHash.toString()).toEqual(
mocks.dummyVerificationKeyHash
);
}
// does not throw an error if private key is missing unless if .send is executed
{
let Local = await Mina.LocalBlockchain({ proofsEnabled: false });
Mina.setActiveInstance(Local);
const [feePayer] = Local.testAccounts;
let tx = await Mina.transaction(feePayer, async () => {
AccountUpdate.fundNewAccount(feePayer);
});
tx.sign([]);
await expect(tx.send()).rejects.toThrow(
'Check signature: Invalid signature on fee payer for key'
);
}
// correctly identifies when neither flag is set
{
let accountUpdate = createAccountUpdateWithMayUseToken({
parentsOwnToken: Bool(false),
inheritFromParent: Bool(false),
});
expect(AccountUpdate.MayUseToken.isNo(accountUpdate).toBoolean()).toEqual(true);
}