Skip to content

Commit 4a6609c

Browse files
committed
Added persistance integration tests
1 parent 3fa53eb commit 4a6609c

File tree

4 files changed

+458
-0
lines changed

4 files changed

+458
-0
lines changed

packages/persistance/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"lint": "eslint ./src ./test",
1313
"test:file": "node --experimental-vm-modules --experimental-wasm-modules --experimental-wasm-threads ../../node_modules/jest/bin/jest.js",
1414
"test": "npm run test:file -- ./test/**",
15+
"integration": "npm run test:file -- ./test-integration/** --runInBand",
1516
"test:watch": "npm run test:file -- ./test/** --watch"
1617
},
1718
"main": "dist/index.js",
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import "reflect-metadata";
2+
import {
3+
afterAll,
4+
afterEach,
5+
beforeAll,
6+
describe,
7+
expect,
8+
} from "@jest/globals";
9+
import { expectDefined, equalProvable } from "@proto-kit/common";
10+
import { Balance, TokenId } from "@proto-kit/library";
11+
import { NetworkState } from "@proto-kit/protocol";
12+
import { AppChainTransaction } from "@proto-kit/sdk";
13+
import { ComputedBlock, UnprovenBlock } from "@proto-kit/sequencer";
14+
import { PrivateKey, PublicKey } from "o1js";
15+
import { container } from "tsyringe";
16+
import {
17+
PrismaBatchStore,
18+
PrismaBlockStorage,
19+
PrismaTransactionStorage
20+
} from "../src";
21+
import {
22+
createPrismaAppchain,
23+
IntegrationTestDBConfig,
24+
prepareBlock
25+
} from "./utils";
26+
27+
describe("Prisma integration", () => {
28+
let appChain: ReturnType<typeof createPrismaAppchain>;
29+
30+
const sender = PrivateKey.random();
31+
let senderNonce = 0;
32+
33+
const setup = async () => {
34+
const { prismaConfig, redisConfig } = IntegrationTestDBConfig;
35+
appChain = createPrismaAppchain(prismaConfig, redisConfig);
36+
37+
appChain.configurePartial({
38+
Signer: {
39+
signer: sender,
40+
},
41+
});
42+
43+
await appChain.start(container.createChildContainer());
44+
45+
const db = appChain.sequencer.resolve("Database");
46+
await db.prisma.clearDatabase();
47+
await db.redis.clearDatabase();
48+
49+
senderNonce = 0;
50+
};
51+
52+
const teardown = async () => {
53+
await appChain.sequencer.resolve("Database").close();
54+
};
55+
56+
describe("produce fuzzed block", () => {
57+
let block: UnprovenBlock | undefined;
58+
let batch: ComputedBlock | undefined;
59+
60+
beforeAll(async () => {
61+
await setup();
62+
63+
await prepareBlock(appChain, sender.toPublicKey(), senderNonce);
64+
senderNonce++;
65+
66+
[block, batch] = await appChain.sequencer
67+
.resolve("BlockTrigger")
68+
.produceBlock();
69+
}, 30000);
70+
71+
afterAll(async () => {
72+
await teardown();
73+
});
74+
75+
it("should have produced a block and batch", () => {
76+
expectDefined(block);
77+
expectDefined(batch);
78+
});
79+
80+
it("should save and retrieve the same block", async () => {
81+
expectDefined(block);
82+
83+
// Check equality of block
84+
const blockStorage = await appChain.sequencer.resolveOrFail(
85+
"UnprovenBlockStorage",
86+
PrismaBlockStorage
87+
);
88+
const retrievedBlock = await blockStorage.getBlockAt(0);
89+
expectDefined(retrievedBlock);
90+
91+
// Check that transactions match
92+
expect(retrievedBlock.transactions).toHaveLength(1);
93+
expect(retrievedBlock.transactions[0].tx.hash().toString()).toStrictEqual(
94+
block.transactions[0].tx.hash().toString()
95+
);
96+
97+
expect(retrievedBlock.hash.toString()).toStrictEqual(
98+
block.hash.toString()
99+
);
100+
101+
equalProvable(
102+
NetworkState.toFields(retrievedBlock.networkState.before),
103+
NetworkState.toFields(block.networkState.before)
104+
);
105+
equalProvable(
106+
NetworkState.toFields(retrievedBlock.networkState.during),
107+
NetworkState.toFields(block.networkState.during)
108+
);
109+
});
110+
111+
it("should save and retrieve the same batch", async () => {
112+
expectDefined(batch);
113+
114+
// Check equality of batch
115+
const batchStorage = await appChain.sequencer.resolveOrFail(
116+
"BlockStorage",
117+
PrismaBatchStore
118+
);
119+
const retrievedBatch = await batchStorage.getBlockAt(0);
120+
expectDefined(retrievedBatch);
121+
122+
expect(retrievedBatch.height).toStrictEqual(batch.height);
123+
expect(retrievedBatch.bundles).toHaveLength(
124+
retrievedBatch.bundles.length
125+
);
126+
expect(retrievedBatch.bundles).toStrictEqual(retrievedBatch.bundles);
127+
});
128+
129+
it("should query fetches correct nonce", async () => {
130+
const accountState =
131+
await appChain.query.protocol.AccountState.accountState.get(
132+
sender.toPublicKey()
133+
);
134+
135+
expectDefined(accountState);
136+
137+
expect(accountState.nonce.toString()).toBe("1");
138+
});
139+
140+
it("should query fetches undefined for unset account", async () => {
141+
const accountState =
142+
await appChain.query.protocol.AccountState.accountState.get(
143+
PublicKey.empty()
144+
);
145+
146+
expect(accountState).toBeUndefined();
147+
});
148+
});
149+
150+
describe("persisted mempool", () => {
151+
let transaction: AppChainTransaction;
152+
153+
beforeAll(async () => {
154+
await setup();
155+
156+
transaction = await prepareBlock(appChain, sender.toPublicKey(), senderNonce);
157+
senderNonce++;
158+
});
159+
160+
afterAll(async () => {
161+
await teardown();
162+
});
163+
164+
it("mempool should give 1 transaction", async () => {
165+
const mempool = appChain.sequencer.resolve("Mempool");
166+
const txs = await mempool.getTxs();
167+
168+
expectDefined(transaction.transaction);
169+
170+
expect(txs).toHaveLength(1);
171+
expect(txs[0].hash().toString()).toStrictEqual(
172+
transaction.transaction.hash().toString()
173+
);
174+
});
175+
176+
it("should resolve transaction from storage as pending", async () => {
177+
const txResolver = appChain.sequencer.resolveOrFail("TransactionStorage", PrismaTransactionStorage);
178+
179+
const txs = await txResolver.getPendingUserTransactions();
180+
181+
expectDefined(transaction.transaction);
182+
183+
expect(txs).toHaveLength(1);
184+
expect(txs[0].hash().toString()).toStrictEqual(
185+
transaction.transaction.hash().toString()
186+
);
187+
});
188+
});
189+
});
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import "reflect-metadata";
2+
import { afterAll, beforeAll, expect } from "@jest/globals";
3+
import { expectDefined, log } from "@proto-kit/common";
4+
import { Field, Poseidon, PrivateKey } from "o1js";
5+
import { container } from "tsyringe";
6+
import {
7+
createPrismaAppchain,
8+
IntegrationTestDBConfig,
9+
prepareBlock,
10+
} from "./utils";
11+
import { Prisma } from "@prisma/client";
12+
13+
log.setLevel("TRACE")
14+
15+
// describe("Decimal", () => {
16+
//
17+
// it("decimal", () => {
18+
// const f = Poseidon.hash([Field(5)])
19+
//
20+
// const Decimal = Prisma.Decimal.clone({
21+
// precision: 78,
22+
// });
23+
//
24+
// const d = new Decimal(f.toString());
25+
// expect(d.toFixed()).toStrictEqual(f.toString())
26+
// })
27+
//
28+
// })
29+
30+
describe("sequencer restart", () => {
31+
let appChain: ReturnType<typeof createPrismaAppchain>;
32+
33+
const sender = PrivateKey.random();
34+
let senderNonce = 0;
35+
36+
const clearDB = async () => {
37+
const db = appChain.sequencer.resolve("Database");
38+
await db.prisma.clearDatabase();
39+
await db.redis.clearDatabase();
40+
};
41+
42+
const setup = async () => {
43+
const { prismaConfig, redisConfig } = IntegrationTestDBConfig;
44+
appChain = createPrismaAppchain(prismaConfig, redisConfig);
45+
46+
appChain.configurePartial({
47+
Signer: {
48+
signer: sender,
49+
},
50+
});
51+
52+
await appChain.start(container.createChildContainer());
53+
54+
senderNonce = 0;
55+
};
56+
57+
const teardown = async () => {
58+
await appChain.sequencer.resolve("Database").close();
59+
};
60+
61+
beforeAll(async () => {
62+
await setup();
63+
await clearDB();
64+
65+
const blockTrigger = appChain.sequencer.resolve("BlockTrigger");
66+
67+
console.log(sender.toPublicKey().toBase58())
68+
69+
for (let block = 0; block < 2; block++) {
70+
await prepareBlock(appChain, sender.toPublicKey(), senderNonce);
71+
senderNonce++;
72+
73+
const [producedBlock] = await blockTrigger.produceBlock();
74+
if ((producedBlock?.transactions.length ?? 0) === 0) {
75+
throw new Error(`Block not produced correctly: ${block}`);
76+
}
77+
}
78+
79+
await teardown();
80+
81+
await setup();
82+
}, 40000);
83+
84+
afterAll(async () => {
85+
await teardown();
86+
});
87+
88+
it("should fetch correct nonce", async () => {
89+
const accountState =
90+
await appChain.query.protocol.AccountState.accountState.get(
91+
sender.toPublicKey()
92+
);
93+
94+
expectDefined(accountState);
95+
96+
expect(accountState.nonce.toString()).toBe("2");
97+
});
98+
99+
it("should be able to produce a block on top", async () => {
100+
const blockTrigger = appChain.sequencer.resolve("BlockTrigger");
101+
await prepareBlock(appChain, sender.toPublicKey(), senderNonce);
102+
senderNonce++;
103+
104+
const [block, batch] = await blockTrigger.produceBlock();
105+
106+
expectDefined(block);
107+
expectDefined(batch);
108+
109+
expect(block.transactions).toHaveLength(1);
110+
expect(block.transactions[0].tx.nonce.toString()).toBe("2");
111+
}, 15000);
112+
});

0 commit comments

Comments
 (0)