116 lines
3.7 KiB
TypeScript
116 lines
3.7 KiB
TypeScript
import NodeWallet from '@project-serum/anchor/dist/cjs/nodewallet';
|
|
import { BN } from 'bn.js';
|
|
import { AnchorProvider } from '@project-serum/anchor';
|
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes';
|
|
import { assert } from 'chai';
|
|
import * as crypto from 'crypto';
|
|
|
|
import {
|
|
createAppendIx,
|
|
deserializeChangeLogEventV1,
|
|
SPL_NOOP_PROGRAM_ID,
|
|
} from '../../src';
|
|
import { MerkleTree } from '../../src/merkle-tree';
|
|
import { execute, createTreeOnChain } from '../utils';
|
|
|
|
describe('Serde tests', () => {
|
|
let offChainTree: MerkleTree;
|
|
let cmtKeypair: Keypair;
|
|
let payerKeypair: Keypair;
|
|
let payer: PublicKey;
|
|
let connection: Connection;
|
|
let provider: AnchorProvider;
|
|
|
|
const MAX_SIZE = 64;
|
|
const MAX_DEPTH = 14;
|
|
|
|
beforeEach(async () => {
|
|
payerKeypair = Keypair.generate();
|
|
payer = payerKeypair.publicKey;
|
|
|
|
connection = new Connection('http://localhost:8899', {
|
|
commitment: 'confirmed',
|
|
});
|
|
const wallet = new NodeWallet(payerKeypair);
|
|
provider = new AnchorProvider(connection, wallet, {
|
|
commitment: connection.commitment,
|
|
skipPreflight: true,
|
|
});
|
|
|
|
await provider.connection.confirmTransaction(
|
|
await provider.connection.requestAirdrop(payer, 1e10),
|
|
'confirmed'
|
|
);
|
|
});
|
|
describe('ChangeLogEvent tests', () => {
|
|
let cmt: PublicKey;
|
|
beforeEach(async () => {
|
|
[cmtKeypair, offChainTree] = await createTreeOnChain(
|
|
provider,
|
|
payerKeypair,
|
|
0,
|
|
{ maxDepth: MAX_DEPTH, maxBufferSize: MAX_SIZE }
|
|
);
|
|
cmt = cmtKeypair.publicKey;
|
|
});
|
|
it('Can deserialize a ChangeLogEvent', async () => {
|
|
const newLeaf = crypto.randomBytes(32);
|
|
const txId = await execute(
|
|
provider,
|
|
[createAppendIx(cmt, payer, newLeaf)],
|
|
[payerKeypair]
|
|
);
|
|
offChainTree.updateLeaf(0, newLeaf);
|
|
|
|
const transaction = await connection.getTransaction(txId, {
|
|
commitment: 'confirmed',
|
|
maxSupportedTransactionVersion: 2,
|
|
});
|
|
|
|
// Get noop program instruction
|
|
const accountKeys = transaction!.transaction.message.getAccountKeys();
|
|
const noopInstruction =
|
|
transaction!.meta!.innerInstructions![0].instructions[0];
|
|
const programId = accountKeys.get(noopInstruction.programIdIndex)!;
|
|
if (!programId.equals(SPL_NOOP_PROGRAM_ID)) {
|
|
throw Error(
|
|
`Only inner ix should be a noop, but instead is a ${programId.toBase58()}`
|
|
);
|
|
}
|
|
const cpiData = Buffer.from(bs58.decode(noopInstruction.data));
|
|
const changeLogEvent = deserializeChangeLogEventV1(cpiData);
|
|
|
|
assert(
|
|
changeLogEvent.treeId.equals(cmt),
|
|
`Tree id in changeLog differs from expected tree ${cmt.toBase58()}`
|
|
);
|
|
assert(
|
|
changeLogEvent.index === 0,
|
|
`ChangeLog should have index 0, but has index ${changeLogEvent.index}`
|
|
);
|
|
assert(
|
|
new BN.BN(changeLogEvent.seq).toNumber() === 1,
|
|
`ChangeLog should have sequence number of 1, but has seq number of ${changeLogEvent.seq.toString()}`
|
|
);
|
|
|
|
// Check that the emitted ChangeLog path matches up with the updated Tree
|
|
let nodeIndex = 0 + (1 << MAX_DEPTH);
|
|
let realTreeNode = offChainTree.leaves[0];
|
|
while (nodeIndex > 0) {
|
|
const clNode = changeLogEvent.path.shift()!;
|
|
assert(
|
|
nodeIndex === clNode.index,
|
|
`Expected changeLog index to be ${nodeIndex} but is ${clNode.index}`
|
|
);
|
|
assert(
|
|
realTreeNode!.node.equals(Buffer.from(clNode.node)),
|
|
`ChangeLog node differs at node index: ${clNode.index}`
|
|
);
|
|
realTreeNode = realTreeNode.parent!;
|
|
nodeIndex = nodeIndex >> 1;
|
|
}
|
|
});
|
|
});
|
|
});
|