Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: photon 0.45.0, add: getValidityProofV0 for custom tree support #1202

Merged
merged 1 commit into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const LIGHT_PROVER_PROCESS_NAME = "light-prover";
export const INDEXER_PROCESS_NAME = "photon";
export const FORESTER_PROCESS_NAME = "forester";

export const PHOTON_VERSION = "0.44.0";
export const PHOTON_VERSION = "0.45.0";

export const LIGHT_PROTOCOL_PROGRAMS_DIR_ENV = "LIGHT_PROTOCOL_PROGRAMS_DIR";
export const BASE_PATH = "../../bin/";
5 changes: 2 additions & 3 deletions js/stateless.js/src/actions/create-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ export async function createAccount(
/// TODO: enforce program-derived
const address = await deriveAddress(seed, addressTree);

/// TODO: pass trees
const proof = await rpc.getValidityProof(undefined, [
bn(address.toBytes()),
const proof = await rpc.getValidityProofV0(undefined, [
{ address: bn(address.toBytes()), tree: addressTree, queue: addressQueue },
]);

const params: NewAddressParams = {
Expand Down
21 changes: 19 additions & 2 deletions js/stateless.js/src/rpc-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ export interface SignatureWithMetadata {
slot: number;
}

export interface HashWithTree {
hash: BN254;
tree: PublicKey;
queue: PublicKey;
}

export interface AddressWithTree {
address: BN254;
tree: PublicKey;
queue: PublicKey;
}

export interface CompressedTransaction {
compressionInfo: {
closedAccounts: {
Expand Down Expand Up @@ -497,9 +509,14 @@ export interface CompressionApiInterface {
newAddresses: BN254[],
): Promise<CompressedProofWithContext>;

getValidityProofV0(
hashes: HashWithTree[],
newAddresses: AddressWithTree[],
): Promise<CompressedProofWithContext>;

getValidityProofAndRpcContext(
hashes: BN254[],
newAddresses: BN254[],
hashes: HashWithTree[],
newAddresses: AddressWithTree[],
): Promise<WithContext<CompressedProofWithContext>>;

getCompressedAccountsByOwner(
Expand Down
73 changes: 58 additions & 15 deletions js/stateless.js/src/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {
WithContext,
GetCompressedAccountsByOwnerConfig,
WithCursor,
AddressWithTree,
HashWithTree,
} from './rpc-interface';
import {
MerkleContextWithMerkleProof,
Expand Down Expand Up @@ -1367,15 +1369,52 @@ export class Rpc extends Connection implements CompressionApiInterface {
*/
async getValidityProof(
hashes: BN254[] = [],
newAddresses: BN254[] = [],
newAddresses: BN254[] = []
): Promise<CompressedProofWithContext> {
const { value } = await this.getValidityProofAndRpcContext(
hashes,
newAddresses,
);
const defaultAddressTreePublicKey = defaultTestStateTreeAccounts().addressTree;
const defaultAddressQueuePublicKey = defaultTestStateTreeAccounts().addressQueue;
const defaultStateTreePublicKey = defaultTestStateTreeAccounts().merkleTree;
const defaultStateQueuePublicKey = defaultTestStateTreeAccounts().nullifierQueue;
const formattedHashes = hashes.map(item => {
if (item instanceof BN) {
return { hash: item, tree: defaultStateTreePublicKey, queue: defaultStateQueuePublicKey };
}
return item;
});

const formattedNewAddresses = newAddresses.map(item => {
if (item instanceof BN) {
return { address: item, tree: defaultAddressTreePublicKey, queue: defaultAddressQueuePublicKey };
}
return item;
});

return this.getValidityProofV0(formattedHashes, formattedNewAddresses);
}

/**
* Fetch the latest validity proof for (1) compressed accounts specified by
* an array of account hashes. (2) new unique addresses specified by an
* array of addresses.
*
* Validity proofs prove the presence of compressed accounts in state trees
* and the non-existence of addresses in address trees, respectively. They
* enable verification without recomputing the merkle proof path, thus
* lowering verification and data costs.
*
* @param hashes Array of { hash: BN254, tree: PublicKey, queue: PublicKey }.
* @param newAddresses Array of { address: BN254, tree: PublicKey, queue: PublicKey }.
* @returns validity proof with context
*/
async getValidityProofV0(
hashes: HashWithTree[] = [],
newAddresses: AddressWithTree[] = []
): Promise<CompressedProofWithContext> {
const { value } = await this.getValidityProofAndRpcContext(hashes, newAddresses);
return value;
}
/**

/**
* Fetch the latest validity proof for (1) compressed accounts specified by
* an array of account hashes. (2) new unique addresses specified by an
* array of addresses. Returns with context slot.
Expand All @@ -1386,21 +1425,25 @@ export class Rpc extends Connection implements CompressionApiInterface {
* lowering verification and data costs.
*
* @param hashes Array of BN254 hashes.
* @param newAddresses Array of BN254 new addresses.
* @param newAddresses Array of BN254 new addresses. Optionally specify the
* tree and queue for each address. Default to public
* state tree/queue.
* @returns validity proof with context
*/
async getValidityProofAndRpcContext(
hashes: BN254[] = [],
newAddresses: BN254[] = [],
hashes: HashWithTree[] = [],
newAddresses: AddressWithTree[] = []
): Promise<WithContext<CompressedProofWithContext>> {

const unsafeRes = await rpcRequest(
this.compressionApiEndpoint,
'getValidityProof',
{
hashes: hashes.map(hash => encodeBN254toBase58(hash)),
newAddresses: newAddresses.map(address =>
encodeBN254toBase58(address),
),
hashes: hashes.map(({ hash }) => encodeBN254toBase58(hash)),
newAddressesWithTrees: newAddresses.map(({ address, tree }) => ({
address: encodeBN254toBase58(address),
tree: tree.toBase58(),
})),
},
);

Expand Down Expand Up @@ -1428,8 +1471,8 @@ export class Rpc extends Connection implements CompressionApiInterface {
merkleTrees: result.merkleTrees,
leafIndices: result.leafIndices,
nullifierQueues: [
...hashes.map(() => mockNullifierQueue),
...newAddresses.map(() => mockAddressQueue),
...hashes.map(({ queue }) => queue),
...newAddresses.map(({ queue }) => queue),
],
rootIndices: result.rootIndices,
roots: result.roots,
Expand Down
26 changes: 23 additions & 3 deletions js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import { MerkleTree } from '../merkle-tree/merkle-tree';
import { getParsedEvents } from './get-parsed-events';
import { defaultTestStateTreeAccounts } from '../../constants';
import {
AddressWithTree,
CompressedTransaction,
GetCompressedAccountsByOwnerConfig,
HashWithTree,
LatestNonVotingSignatures,
LatestNonVotingSignaturesPaginated,
SignatureWithMetadata,
Expand Down Expand Up @@ -589,11 +591,14 @@ export class TestRpc extends Connection implements CompressionApiInterface {
* {@link getValidityProof} instead.
*/
async getValidityProofAndRpcContext(
hashes: BN254[] = [],
newAddresses: BN254[] = [],
hashes: HashWithTree[] = [],
newAddresses: AddressWithTree[] = [],
): Promise<WithContext<CompressedProofWithContext>> {
if (newAddresses.some(address => !(address instanceof BN))) {
throw new Error('AddressWithTree is not supported in test-rpc');
}
return {
value: await this.getValidityProof(hashes, newAddresses),
value: await this.getValidityProofV0(hashes, newAddresses),
context: { slot: 1 },
};
}
Expand All @@ -615,6 +620,10 @@ export class TestRpc extends Connection implements CompressionApiInterface {
hashes: BN254[] = [],
newAddresses: BN254[] = [],
): Promise<CompressedProofWithContext> {

if (newAddresses.some(address => !(address instanceof BN))) {
throw new Error('AddressWithTree is not supported in test-rpc');
}
let validityProof: CompressedProofWithContext;

if (hashes.length === 0 && newAddresses.length === 0) {
Expand Down Expand Up @@ -737,4 +746,15 @@ export class TestRpc extends Connection implements CompressionApiInterface {

return validityProof;
}

async getValidityProofV0(
hashes: HashWithTree[] = [],
newAddresses: AddressWithTree[] = [],
): Promise<CompressedProofWithContext> {
/// TODO(swen): add support for custom trees
return this.getValidityProof(
hashes.map(hash => hash.hash),
newAddresses.map(address => address.address),
);
}
}
3 changes: 2 additions & 1 deletion js/stateless.js/tests/e2e/compress.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ function txFees(

return totalFee.toNumber();
}

/// TODO: add test case for payer != address
describe('compress', () => {
const { merkleTree } = defaultTestStateTreeAccounts();
Expand All @@ -73,7 +74,7 @@ describe('compress', () => {

it('should create account with address', async () => {
const preCreateAccountsBalance = await rpc.getBalance(payer.publicKey);

await createAccount(
rpc as TestRpc,
payer,
Expand Down
3 changes: 2 additions & 1 deletion js/stateless.js/tests/e2e/rpc-interop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -641,9 +641,10 @@ describe('rpc-interop', () => {
it('getCompressedAccount with address param should work ', async () => {
const seed = new Uint8Array(randomBytes(32));
const addressTree = defaultTestStateTreeAccounts().addressTree;
const addressQueue = defaultTestStateTreeAccounts().addressQueue;
const address = await deriveAddress(seed, addressTree);

await createAccount(rpc, payer, seed, LightSystemProgram.programId);
await createAccount(rpc, payer, seed, LightSystemProgram.programId, addressTree, addressQueue);

// fetch the owners latest account
const accounts = await rpc.getCompressedAccountsByOwner(
Expand Down
2 changes: 1 addition & 1 deletion scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ VERSIONS=(
"solana:1.18.22"
"anchor:anchor-v0.29.0"
"jq:jq-1.7.1"
"photon:0.44.0"
"photon:0.45.0"
)

# Architecture-specific suffixes
Expand Down