o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
297 lines (262 loc) • 9.68 kB
text/typescript
import { UInt64, Mina, AccountUpdate, PublicKey, Field, TokenId, PrivateKey } from 'o1js';
import { describe, it, before, beforeEach, afterEach } from 'node:test';
import { expect } from 'expect';
const defaultNetwork = Mina.Network({
networkId: 'testnet',
mina: 'https://example.com/graphql',
archive: 'https://example.com//graphql',
});
const enforcedNetwork = Mina.Network({
networkId: 'testnet',
mina: 'https://example.com/graphql',
archive: 'https://example.com//graphql',
bypassTransactionLimits: false,
});
const unlimitedNetwork = Mina.Network({
networkId: 'testnet',
mina: 'https://unlimited.com/graphql',
archive: 'https://unlimited.com//graphql',
bypassTransactionLimits: true,
});
const networkWithHeaders = Mina.Network({
networkId: 'testnet',
mina: 'https://mina.dummy/graphql',
archive: 'https://archive.dummy/graphql',
minaDefaultHeaders: {
Authorization: 'Bearer mina-default-token',
'X-Test': 'mina-test',
},
archiveDefaultHeaders: {
Authorization: 'Bearer archive-default-token',
'X-Test': 'archive-test',
},
});
describe('Test default network', () => {
let bobAccount: PublicKey, bobKey: PrivateKey;
before(async () => {
Mina.setActiveInstance(defaultNetwork);
bobKey = PrivateKey.random();
bobAccount = bobKey.toPublicKey();
});
it('Simple account update', async () => {
let txn = await Mina.transaction(async () => {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(1));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
});
it('Multiple account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 2; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
});
it('More than limit account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 12; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
// failure with default bypassTransactionLimits value
await expect(txn.sign([bobKey]).safeSend()).rejects.toThrow();
});
});
describe('Test enforced network', () => {
let bobAccount: PublicKey, bobKey: PrivateKey;
before(async () => {
Mina.setActiveInstance(enforcedNetwork);
bobKey = PrivateKey.random();
bobAccount = bobKey.toPublicKey();
});
it('Simple account update', async () => {
let txn = await Mina.transaction(async () => {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(1));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
});
it('Multiple account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 2; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
});
it('More than limit account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 12; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
// failure with bypassTransactionLimits = false
await expect(txn.sign([bobKey]).safeSend()).rejects.toThrow();
});
});
describe('Test unlimited network', () => {
let bobAccount: PublicKey, bobKey: PrivateKey;
before(async () => {
Mina.setActiveInstance(unlimitedNetwork);
bobKey = PrivateKey.random();
bobAccount = bobKey.toPublicKey();
});
it('Simple account update', async () => {
let txn = await Mina.transaction(async () => {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(1));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
});
it('Multiple account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 2; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
});
it('More than limit account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 12; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
// success with bypassTransactionLimits = true
await txn.sign([bobKey]).safeSend();
});
});
describe('Test network with headers', () => {
let bobAccount: PublicKey, bobKey: PrivateKey;
let originalFetch: typeof global.fetch;
let lastFetchOptions: any = null;
before(async () => {
Mina.setActiveInstance(networkWithHeaders);
bobKey = PrivateKey.random();
bobAccount = bobKey.toPublicKey();
});
beforeEach(() => {
originalFetch = global.fetch;
lastFetchOptions = undefined;
global.fetch = ((input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
lastFetchOptions = init;
let url: string;
if (typeof input === 'string') {
url = input;
} else if (input instanceof URL) {
url = input.toString();
} else {
url = input.url;
}
if (url.includes('archive.dummy')) {
return Promise.resolve({
ok: true,
json: async () => ({
data: {
events: [],
},
}),
} as Response);
} else {
return Promise.resolve({
ok: true,
json: async () => ({
data: {},
}),
} as Response);
}
}) as typeof fetch;
});
afterEach(() => {
global.fetch = originalFetch;
lastFetchOptions = null;
});
it('Simple account update', async () => {
let txn = await Mina.transaction(async () => {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(1));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
// we can check the headers here too
// expect(lastFetchOptions.headers).toEqual({
// Authorization: 'Bearer archive-default-token',
// 'Content-Type': 'application/json',
// 'X-Test': 'archive-test',
// });
});
it('Multiple account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 2; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
await txn.sign([bobKey]).safeSend();
});
it('More than limit account update', async () => {
let txn = await Mina.transaction(async () => {
for (let index = 0; index < 12; index++) {
const accountUpdateBob = AccountUpdate.create(bobAccount, Field.from(index));
accountUpdateBob.account.balance.requireEquals(UInt64.zero);
accountUpdateBob.balance.addInPlace(UInt64.one);
}
});
await txn.prove();
await expect(txn.sign([bobKey]).safeSend()).rejects.toThrow();
});
it('Archive default headers with fetchActions', async () => {
await Mina.fetchActions(bobAccount);
expect(lastFetchOptions.headers).toMatchObject({
'Content-Type': 'application/json',
Authorization: 'Bearer archive-default-token',
'X-Test': 'archive-test',
});
});
it('Archive default headers with fetchEvents', async () => {
await Mina.fetchEvents(bobAccount, TokenId.empty());
expect(lastFetchOptions.headers).toMatchObject({
'Content-Type': 'application/json',
Authorization: 'Bearer archive-default-token',
'X-Test': 'archive-test',
});
});
it('Archive default headers with per request headers in fetchActions', async () => {
await Mina.fetchActions(bobAccount, undefined, undefined, undefined, undefined, {
'X-Test': 'per-request-test',
});
expect(lastFetchOptions.headers).toMatchObject({
'Content-Type': 'application/json',
Authorization: 'Bearer archive-default-token',
'X-Test': 'per-request-test',
});
});
});