Skip to content

Commit

Permalink
test: AztecRPC API using sandbox (#1568)
Browse files Browse the repository at this point in the history
Fixes
[#1504](#1504)
  • Loading branch information
benesjan authored Aug 17, 2023
1 parent fb45c06 commit b2662db
Show file tree
Hide file tree
Showing 21 changed files with 325 additions and 123 deletions.
13 changes: 13 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,17 @@ jobs:
name: "Test"
command: cond_spot_run_tests end-to-end e2e_aztec_js_browser.test.ts docker-compose-e2e-sandbox.yml

aztec-rpc-sandbox:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: cond_spot_run_tests end-to-end aztec_rpc_sandbox.test.ts docker-compose-e2e-sandbox.yml

e2e-canary-test:
docker:
- image: aztecprotocol/alpine-build-image
Expand Down Expand Up @@ -1307,6 +1318,7 @@ workflows:
- e2e-p2p: *e2e_test
- e2e-canary-test: *e2e_test
- e2e-browser-sandbox: *e2e_test
- aztec-rpc-sandbox: *e2e_test

- e2e-end:
requires:
Expand All @@ -1332,6 +1344,7 @@ workflows:
- e2e-p2p
- e2e-browser-sandbox
- e2e-canary-test
- aztec-rpc-sandbox
<<: *defaults

- deploy-dockerhub:
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class AztecNodeService implements AztecNode {
// first create and sync the archiver
const archiver = await Archiver.createAndSync(config);

// we idenfity the P2P transaction protocol by using the rollup contract address.
// we identify the P2P transaction protocol by using the rollup contract address.
// this may well change in future
config.transactionProtocol = `/aztec/tx/${config.rollupContract.toString()}`;

Expand Down

This file was deleted.

14 changes: 6 additions & 8 deletions yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,9 @@ export class AztecRPCServer implements AztecRPC {
return accounts;
}

public async getAccount(address: AztecAddress): Promise<CompleteAddress> {
public async getAccount(address: AztecAddress): Promise<CompleteAddress | undefined> {
const result = await this.getAccounts();
const account = result.find(r => r.address.equals(address));
if (!account) {
throw new Error(`Unable to get complete address for address ${address.toString()}`);
}
return Promise.resolve(account);
}

Expand All @@ -123,12 +120,9 @@ export class AztecRPCServer implements AztecRPC {
return recipients;
}

public async getRecipient(address: AztecAddress): Promise<CompleteAddress> {
public async getRecipient(address: AztecAddress): Promise<CompleteAddress | undefined> {
const result = await this.getRecipients();
const recipient = result.find(r => r.address.equals(address));
if (!recipient) {
throw new Error(`Unable to get complete address for address ${address.toString()}`);
}
return Promise.resolve(recipient);
}

Expand All @@ -142,6 +136,10 @@ export class AztecRPCServer implements AztecRPC {
}
}

public async getContracts(): Promise<AztecAddress[]> {
return (await this.db.getContracts()).map(c => c.address);
}

public async getPublicStorageAt(contract: AztecAddress, storageSlot: Fr) {
if ((await this.getContractData(contract)) === undefined) {
throw new Error(`Contract ${contract.toString()} is not deployed`);
Expand Down
1 change: 1 addition & 0 deletions yarn-project/aztec-rpc/src/aztec_rpc_server/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './aztec_rpc_server.js';
export * from './create_aztec_rpc_server.js';
export { aztecRpcTestSuite } from './test/aztec_rpc_test_suite.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Grumpkin } from '@aztec/circuits.js/barretenberg';
import { TestKeyStore } from '@aztec/key-store';
import { AztecNode, AztecRPC } from '@aztec/types';

import { mock } from 'jest-mock-extended';

import { MemoryDB } from '../../database/memory_db.js';
import { EthAddress, RpcServerConfig } from '../../index.js';
import { AztecRPCServer } from '../aztec_rpc_server.js';
import { aztecRpcTestSuite } from './aztec_rpc_test_suite.js';

async function createAztecRpcServer(): Promise<AztecRPC> {
const keyStore = new TestKeyStore(await Grumpkin.new());
const node = mock<AztecNode>();
const db = new MemoryDB();
const config: RpcServerConfig = {
l2BlockPollingIntervalMS: 100,
};

// Setup the relevant mocks
node.getBlockHeight.mockResolvedValue(2);
node.getVersion.mockResolvedValue(1);
node.getChainId.mockResolvedValue(1);
node.getRollupAddress.mockResolvedValue(EthAddress.random());

return new AztecRPCServer(keyStore, node, db, config);
}

aztecRpcTestSuite('AztecRPCServer', createAztecRpcServer);
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { AztecAddress, CompleteAddress, Fr, FunctionData, TxContext } from '@aztec/circuits.js';
import { Grumpkin } from '@aztec/circuits.js/barretenberg';
import { ConstantKeyPair } from '@aztec/key-store';
import {
AztecRPC,
DeployedContract,
INITIAL_L2_BLOCK_NUM,
TxExecutionRequest,
randomDeployedContract,
} from '@aztec/types';

export const aztecRpcTestSuite = (testName: string, aztecRpcSetup: () => Promise<AztecRPC>) => {
describe(testName, function () {
let rpc: AztecRPC;

beforeAll(async () => {
rpc = await aztecRpcSetup();
}, 120_000);

it('registers an account and returns it as an account only and not as a recipient', async () => {
const keyPair = ConstantKeyPair.random(await Grumpkin.new());
const completeAddress = await CompleteAddress.fromPrivateKey(await keyPair.getPrivateKey());

await rpc.registerAccount(await keyPair.getPrivateKey(), completeAddress);

// Check that the account is correctly registered using the getAccounts and getRecipients methods
const accounts = await rpc.getAccounts();
const recipients = await rpc.getRecipients();
expect(accounts).toContainEqual(completeAddress);
expect(recipients).not.toContainEqual(completeAddress);

// Check that the account is correctly registered using the getAccount and getRecipient methods
const account = await rpc.getAccount(completeAddress.address);
const recipient = await rpc.getRecipient(completeAddress.address);
expect(account).toEqual(completeAddress);
expect(recipient).toBeUndefined();
});

it('registers a recipient and returns it as a recipient only and not as an account', async () => {
const completeAddress = await CompleteAddress.random();

await rpc.registerRecipient(completeAddress);

// Check that the recipient is correctly registered using the getAccounts and getRecipients methods
const accounts = await rpc.getAccounts();
const recipients = await rpc.getRecipients();
expect(accounts).not.toContainEqual(completeAddress);
expect(recipients).toContainEqual(completeAddress);

// Check that the recipient is correctly registered using the getAccount and getRecipient methods
const account = await rpc.getAccount(completeAddress.address);
const recipient = await rpc.getRecipient(completeAddress.address);
expect(account).toBeUndefined();
expect(recipient).toEqual(completeAddress);
});

it('cannot register the same account twice', async () => {
const keyPair = ConstantKeyPair.random(await Grumpkin.new());
const completeAddress = await CompleteAddress.fromPrivateKey(await keyPair.getPrivateKey());

await rpc.registerAccount(await keyPair.getPrivateKey(), completeAddress);
await expect(async () => rpc.registerAccount(await keyPair.getPrivateKey(), completeAddress)).rejects.toThrow(
`Complete address corresponding to ${completeAddress.address} already exists`,
);
});

it('cannot register the same recipient twice', async () => {
const completeAddress = await CompleteAddress.random();

await rpc.registerRecipient(completeAddress);
await expect(() => rpc.registerRecipient(completeAddress)).rejects.toThrow(
`Complete address corresponding to ${completeAddress.address} already exists`,
);
});

it('successfully adds a contract', async () => {
const contracts: DeployedContract[] = [randomDeployedContract(), randomDeployedContract()];
await rpc.addContracts(contracts);

const expectedContractAddresses = contracts.map(contract => contract.address);
const contractAddresses = await rpc.getContracts();

// check if all the contracts were returned
expect(contractAddresses).toEqual(expect.arrayContaining(expectedContractAddresses));
});

it('throws when simulating a tx targeting public entrypoint', async () => {
const functionData = FunctionData.empty();
functionData.isPrivate = false;
const txExecutionRequest = new TxExecutionRequest(
AztecAddress.random(),
functionData,
new Fr(0),
TxContext.empty(),
[],
);

await expect(async () => await rpc.simulateTx(txExecutionRequest)).rejects.toThrow(
'Public entrypoints are not allowed',
);
});

// Note: Not testing a successful run of `simulateTx`, `sendTx`, `getTxReceipt` and `viewTx` here as it requires
// a larger setup and it's sufficiently tested in the e2e tests.

it('throws when getting public storage for non-existent contract', async () => {
const contract = AztecAddress.random();
await expect(async () => await rpc.getPublicStorageAt(contract, new Fr(0n))).rejects.toThrow(
`Contract ${contract.toString()} is not deployed`,
);
});

// Note: Not testing `getContractDataAndBytecode`, `getContractData` and `getUnencryptedLogs` here as these
// functions only call AztecNode and these methods are frequently used by the e2e tests.

it('successfully gets a block number', async () => {
const blockNum = await rpc.getBlockNum();
expect(blockNum).toBeGreaterThanOrEqual(INITIAL_L2_BLOCK_NUM);
});

it('successfully gets node info', async () => {
const nodeInfo = await rpc.getNodeInfo();
expect(nodeInfo.version).toBeDefined();
expect(nodeInfo.chainId).toBeDefined();
expect(nodeInfo.rollupAddress).toBeDefined();
});

// Note: Not testing `isGlobalStateSynchronised`, `isAccountStateSynchronised` and `getSyncStatus` as these methods
// only call synchroniser.
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ export class MemoryContractDatabase implements ContractDatabase {
* @param address - The AztecAddress to search for in the stored contracts.
* @returns A Promise resolving to the ContractDao instance matching the given address or undefined.
*/
public getContract(address: AztecAddress) {
public getContract(address: AztecAddress): Promise<ContractDao | undefined> {
return Promise.resolve(this.contracts.find(c => c.address.equals(address)));
}

public getContracts(): Promise<ContractDao[]> {
return Promise.resolve(this.contracts);
}

/**
* Retrieve the bytecode associated with a given contract address and function selector.
* This function searches through the stored contracts to find a matching contract and function,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class EntrypointCollection implements Entrypoint {

/**
* Registers an entrypoint against an aztec address
* @param addr - The aztec address agianst which to register the implementation.
* @param addr - The aztec address against which to register the implementation.
* @param impl - The entrypoint to be registered.
*/
public registerAccount(addr: AztecAddress, impl: Entrypoint) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '@aztec/types';

export { mustSucceedFetch } from '@aztec/foundation/json-rpc/client';
export { mustSucceedFetchUnlessNoRetry } from '@aztec/foundation/json-rpc/client';

export const createAztecRpcClient = (url: string, fetch = defaultFetch): AztecRPC =>
createJsonRpcClient<AztecRPC>(
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export abstract class BaseWallet implements Wallet {
addContracts(contracts: DeployedContract[]): Promise<void> {
return this.rpc.addContracts(contracts);
}
getContracts(): Promise<AztecAddress[]> {
return this.rpc.getContracts();
}
simulateTx(txRequest: TxExecutionRequest): Promise<Tx> {
return this.rpc.simulateTx(txRequest);
}
Expand Down
Loading

0 comments on commit b2662db

Please sign in to comment.