Skip to content

Commit

Permalink
fix: flaky e2e sample dapp and quick start (#8768)
Browse files Browse the repository at this point in the history
This fixes the flakiness of `up_quick_start` and `sample_dapp`. It also
updates the test using the cli to the correct version.

One notable source of flakiness that I chased down was a weird`Assertion
failed: membership check failed`. This was showing up pretty reliably in
`sample_dapp`. I solved this by separating the tests, and confirmed by
running it in band (thanks @Thunkar) because it seems like crosstalk
between both tests hitting the same pxe is a trigger of this. I explored
but did not find the actual cause on why the crosstalk would induce this
error, as I had spent already too much time but I have made an issue and
have linked it in the code.
  • Loading branch information
sklppy88 authored Sep 30, 2024
1 parent 0354706 commit 48914ba
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 112 deletions.
2 changes: 1 addition & 1 deletion yarn-project/cli-wallet/src/cmds/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export async function deploy(
partialAddress: partialAddress.toString(),
initializationHash: instance.initializationHash.toString(),
salt: salt.toString(),
transactionFee: deployed.transactionFee,
transactionFee: deployed.transactionFee?.toString(),
});
} else {
log(`Contract deployed at ${address.toString()}`);
Expand Down
19 changes: 11 additions & 8 deletions yarn-project/end-to-end/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -222,15 +222,18 @@ guides-dapp-testing:
LOCALLY
RUN ./scripts/e2e_compose_test.sh guides/dapp_testing.test.ts

# TODO intermittent failure
# guides-sample-dapp:
# LOCALLY
# RUN ./scripts/e2e_compose_test.sh sample-dapp
# The two tests below need to be separated, because there is some crosstalk between the two. TODO (#8813): Figure out why.
guides-sample-dapp-ci:
LOCALLY
RUN ./scripts/e2e_compose_test.sh sample-dapp/ci/index.test.mjs

# TODO currently hangs for hour+
# guides-up-quick-start:
# LOCALLY
# RUN ./scripts/e2e_compose_test.sh guides/up_quick_start.test.ts
guides-sample-dapp:
LOCALLY
RUN ./scripts/e2e_compose_test.sh sample-dapp/index.test.mjs

guides-up-quick-start:
LOCALLY
RUN ./scripts/e2e_compose_test.sh guides/up_quick_start.test.ts

bench-publish-rollup:
LOCALLY
Expand Down
82 changes: 34 additions & 48 deletions yarn-project/end-to-end/src/guides/up_quick_start.sh
Original file line number Diff line number Diff line change
@@ -1,74 +1,60 @@
#!/bin/bash
# Run locally from end-to-end folder while running anvil and sandbox with:
# PATH=$PATH:../node_modules/.bin ./src/guides/up_quick_start.sh

set -eux

LOCATION=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
export WALLET_DATA_DIRECTORY="${LOCATION}/up_quick_start"

aztec-wallet() {
node --no-warnings ../cli-wallet/dest/bin/index.js "$@"
}

# docs:start:declare-accounts
ACCOUNTS=$(aztec-cli get-accounts --json | jq -r '.[].address')
ALICE=$(echo "$ACCOUNTS" | sed -n 1p)
BOB=$(echo "$ACCOUNTS" | sed -n 2p)
ALICE_PRIVATE_KEY="0x2153536ff6628eee01cf4024889ff977a18d9fa61d0e414422f7681cf085c281"
aztec-wallet create-account -a alice
aztec-wallet create-account -a bob
# docs:end:declare-accounts

# docs:start:deploy
CONTRACT=$(aztec-cli deploy TokenContractArtifact --private-key $ALICE_PRIVATE_KEY --salt 0 --args $ALICE "TokenName" "TKN" 18 --json | jq -r '.address')
echo "Deployed contract at $CONTRACT"
aztec-cli check-deploy --contract-address $CONTRACT
DEPLOY_OUTPUT=$(aztec-wallet deploy ../noir-contracts.js/artifacts/token_contract-Token.json --args accounts:alice Test TST 18 -f alice)
TOKEN_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oE 'Contract deployed at 0x[0-9a-fA-F]+' | cut -d ' ' -f4)
echo "Deployed contract at $TOKEN_ADDRESS"
# docs:end:deploy

# docs:start:mint-private
SECRET="0x29bf6afaf29f61cbcf2a4fa7da97be481fb418dc08bdab5338839974beb7b49f"
SECRET_HASH="0x0921759afa747c9073f75df9688a17d271cef0d6ec51eacf70e112402c4db6cd"
MINT_AMOUNT=69
aztec-wallet create-secret -a shield

MINT_PRIVATE_OUTPUT=$(aztec-cli send mint_private \
--args 1000 $SECRET_HASH \
--contract-artifact TokenContractArtifact \
--contract-address $CONTRACT \
--private-key $ALICE_PRIVATE_KEY)
aztec-wallet send mint_private -ca last --args $MINT_AMOUNT secrets:shield:hash -f alice

MINT_PRIVATE_TX_HASH=$(echo "$MINT_PRIVATE_OUTPUT" | grep "Transaction hash:" | awk '{print $NF}')
aztec-wallet add-note TransparentNote pending_shields -ca last -t last -a alice -b $MINT_AMOUNT secrets:shield:hash

aztec-cli add-note \
$ALICE $CONTRACT 5 84114971101151129711410111011678111116101 $MINT_PRIVATE_TX_HASH \
--note 1000 $SECRET_HASH

aztec-cli send redeem_shield \
--args $ALICE 1000 $SECRET \
--contract-artifact TokenContractArtifact \
--contract-address $CONTRACT \
--private-key $ALICE_PRIVATE_KEY
aztec-wallet send redeem_shield -ca last --args accounts:alice $MINT_AMOUNT secrets:shield -f alice
# docs:end:mint-private

# docs:start:get-balance
aztec-cli call balance_of_private \
--args $ALICE \
--contract-artifact TokenContractArtifact \
--contract-address $CONTRACT
ALICE_BALANCE=$(aztec-wallet simulate balance_of_private -ca last --args accounts:alice -f alice)
if ! echo $ALICE_BALANCE | grep -q $MINT_AMOUNT; then
echo "Incorrect Alice balance after transaction (expected $MINT_AMOUNT but got $ALICE_BALANCE)"
exit 1
fi
# docs:end:get-balance

# docs:start:transfer
aztec-cli send transfer \
--args $ALICE $BOB 500 0 \
--contract-artifact TokenContractArtifact \
--contract-address $CONTRACT \
--private-key $ALICE_PRIVATE_KEY
TRANSFER_AMOUNT=42

aztec-cli call balance_of_private \
--args $ALICE \
--contract-artifact TokenContractArtifact \
--contract-address $CONTRACT

aztec-cli call balance_of_private \
--args $BOB \
--contract-artifact TokenContractArtifact \
--contract-address $CONTRACT
aztec-wallet send transfer -ca last --args accounts:bob $TRANSFER_AMOUNT -f alice
# docs:end:transfer

aztec-cli get-logs

# Test end result
BOB_BALANCE=$(aztec-cli call balance_of_private --args $BOB --contract-artifact TokenContractArtifact --contract-address $CONTRACT)
if ! echo $BOB_BALANCE | grep -q 500; then
echo "Incorrect Bob balance after transaction (expected 500 but got $BOB_BALANCE)"
ALICE_BALANCE=$(aztec-wallet simulate balance_of_private -ca last --args accounts:alice -f alice)
if ! echo $ALICE_BALANCE | grep -q "$(($MINT_AMOUNT - $TRANSFER_AMOUNT))"; then
echo "Incorrect Alice balance after transaction (expected 27 but got $ALICE_BALANCE)"
exit 1
fi

BOB_BALANCE=$(aztec-wallet simulate balance_of_private -ca last --args accounts:bob -f bob)
if ! echo $BOB_BALANCE | grep -q $TRANSFER_AMOUNT; then
echo "Incorrect Bob balance after transaction (expected $TRANSFER_AMOUNT but got $BOB_BALANCE)"
exit 1
fi
13 changes: 5 additions & 8 deletions yarn-project/end-to-end/src/guides/up_quick_start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ const { PXE_URL = '' } = process.env;
// Entrypoint for running the up-quick-start script on the CI
describe('guides/up_quick_start', () => {
// TODO: update to not use CLI
it.skip('works', async () => {
it('works', async () => {
await waitForPXE(createPXEClient(PXE_URL));
execSync(
`DEBUG="aztec:*" PXE_URL=\${PXE_URL:-http://localhost:8080} PATH=$PATH:../node_modules/.bin ./src/guides/up_quick_start.sh`,
{
shell: '/bin/bash',
stdio: 'inherit',
},
);
execSync(`DEBUG="aztec:*" PXE_URL=\${PXE_URL:-http://localhost:8080} ./src/guides/up_quick_start.sh`, {
shell: '/bin/bash',
stdio: 'inherit',
});
});
});
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createPXEClient, waitForPXE } from '@aztec/aztec.js';
import { deploy } from '../deploy.mjs';
import { main } from '../index.mjs';

const { PXE_URL = '' } = process.env;
const { PXE_URL = 'http://localhost:8080' } = process.env;

// Tests on our CI that all scripts included in the guide work fine
describe('sample-dapp', () => {
Expand Down
6 changes: 3 additions & 3 deletions yarn-project/end-to-end/src/sample-dapp/contracts.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { AztecAddress, Contract, loadContractArtifact } from '@aztec/aztec.js';
import TokenContractJson from '@aztec/noir-contracts.js/artifacts/token_contract-Token' assert { type: 'json' };
import { AztecAddress } from '@aztec/aztec.js';
import { TokenContract } from '@aztec/noir-contracts.js/Token';

import { readFileSync } from 'fs';

// docs:start:get-tokens
export async function getToken(client) {
const addresses = JSON.parse(readFileSync('addresses.json'));
return Contract.at(AztecAddress.fromString(addresses.token), loadContractArtifact(TokenContractJson), client);
return TokenContract.at(AztecAddress.fromString(addresses.token), client);
}
// docs:end:get-tokens
13 changes: 6 additions & 7 deletions yarn-project/end-to-end/src/sample-dapp/deploy.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getInitialTestAccountsWallets } from '@aztec/accounts/testing';
import { Contract, createPXEClient, loadContractArtifact } from '@aztec/aztec.js';
import TokenContractJson from '@aztec/noir-contracts.js/artifacts/token_contract-Token' assert { type: 'json' };
import { Contract, createPXEClient, loadContractArtifact, waitForPXE } from '@aztec/aztec.js';
import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js';

import { writeFileSync } from 'fs';
import { fileURLToPath } from 'url';
Expand All @@ -10,13 +10,12 @@ const { PXE_URL = 'http://localhost:8080' } = process.env;

async function main() {
const pxe = createPXEClient(PXE_URL);
await waitForPXE(pxe);

const [ownerWallet] = await getInitialTestAccountsWallets(pxe);
const ownerAddress = ownerWallet.getCompleteAddress();
const ownerAddress = ownerWallet.getAddress();

const TokenContractArtifact = loadContractArtifact(TokenContractJson);
const token = await Contract.deploy(ownerWallet, TokenContractArtifact, [ownerAddress, 'TokenName', 'TKN', 18])
.send()
.deployed();
const token = await TokenContract.deploy(ownerWallet, ownerAddress, 'TokenName', 'TKN', 18).send().deployed();

console.log(`Token deployed at ${token.address.toString()}`);

Expand Down
43 changes: 22 additions & 21 deletions yarn-project/end-to-end/src/sample-dapp/index.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getInitialTestAccountsWallets } from '@aztec/accounts/testing';
import { ExtendedNote, Fr, Note, computeSecretHash, createPXEClient } from '@aztec/aztec.js';
import { ExtendedNote, Fr, Note, computeSecretHash, createPXEClient, waitForPXE } from '@aztec/aztec.js';
import { fileURLToPath } from '@aztec/foundation/url';
import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token';

import { getToken } from './contracts.mjs';

Expand All @@ -14,9 +15,11 @@ async function showAccounts(pxe) {
}

async function showPrivateBalances(pxe) {
const [owner] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

// docs:start:showPrivateBalances
const accounts = await pxe.getRegisteredAccounts();
const token = await getToken(pxe);

for (const account of accounts) {
// highlight-next-line:showPrivateBalances
Expand All @@ -37,19 +40,16 @@ async function mintPrivateFunds(pxe) {
const secretHash = await computeSecretHash(secret);
const receipt = await token.methods.mint_private(mintAmount, secretHash).send().wait();

const storageSlot = token.artifact.storageLayout['pending_shields'].slot;
const noteTypeId = token.artifact.notes['TransparentNote'].id;

const note = new Note([new Fr(mintAmount), secretHash]);
const extendedNote = new ExtendedNote(
note,
owner.getAddress(),
token.address,
storageSlot,
noteTypeId,
TokenContract.storage.pending_shields.slot,
TokenContract.notes.TransparentNote.id,
receipt.txHash,
);
await pxe.addNote(extendedNote);
await pxe.addNote(extendedNote, owner.getAddress());

await token.methods.redeem_shield(owner.getAddress(), mintAmount, secret).send().wait();

Expand All @@ -61,21 +61,21 @@ async function transferPrivateFunds(pxe) {
const [owner, recipient] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

const tx = token.methods.transfer(owner.getAddress(), recipient.getAddress(), 1n, 0).send();
console.log(`Sent transfer transaction ${await tx.getTxHash()}`);
await showPrivateBalances(pxe);
console.log(`Sending transaction, awaiting transaction to be mined`);
const receipt = await token.methods.transfer(recipient.getAddress(), 1).send().wait();

console.log(`Awaiting transaction to be mined`);
const receipt = await tx.wait();
console.log(`Transaction has been mined on block ${receipt.blockNumber}`);
console.log(`Transaction ${receipt.txHash} has been mined on block ${receipt.blockNumber}`);
await showPrivateBalances(pxe);
// docs:end:transferPrivateFunds
}

async function showPublicBalances(pxe) {
const [owner] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

// docs:start:showPublicBalances
const accounts = await pxe.getRegisteredAccounts();
const token = await getToken(pxe);

for (const account of accounts) {
// highlight-next-line:showPublicBalances
Expand All @@ -90,13 +90,12 @@ async function mintPublicFunds(pxe) {
const [owner] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

const tx = token.methods.mint_public(owner.getAddress(), 100n).send();
console.log(`Sent mint transaction ${await tx.getTxHash()}`);
await showPublicBalances(pxe);

console.log(`Awaiting transaction to be mined`);
const receipt = await tx.wait();
console.log(`Transaction has been mined on block ${receipt.blockNumber}`);
console.log(`Sending transaction, awaiting transaction to be mined`);
const receipt = await token.methods.mint_public(owner.getAddress(), 100).send().wait();
console.log(`Transaction ${receipt.txHash} has been mined on block ${receipt.blockNumber}`);

await showPublicBalances(pxe);
// docs:end:mintPublicFunds

Expand All @@ -110,8 +109,10 @@ async function mintPublicFunds(pxe) {

async function main() {
const pxe = createPXEClient(PXE_URL);
const { chainId } = await pxe.getNodeInfo();
console.log(`Connected to chain ${chainId}`);
await waitForPXE(pxe);

const { l1ChainId } = await pxe.getNodeInfo();
console.log(`Connected to chain ${l1ChainId}`);

await showAccounts(pxe);

Expand Down
27 changes: 13 additions & 14 deletions yarn-project/end-to-end/src/sample-dapp/index.test.mjs
Original file line number Diff line number Diff line change
@@ -1,49 +1,48 @@
import { createAccount } from '@aztec/accounts/testing';
import { Contract, ExtendedNote, Fr, Note, computeSecretHash, createPXEClient, waitForPXE } from '@aztec/aztec.js';
import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token';

const { PXE_URL = 'http://localhost:8080', ETHEREUM_HOST = 'http://localhost:8545' } = process.env;

describe('token', () => {
// docs:start:setup
let owner, recipient, token;

beforeAll(async () => {
const pxe = createPXEClient(PXE_URL);
await waitForPXE(pxe);
owner = await createAccount(pxe);
recipient = await createAccount(pxe);

token = await Contract.deploy(owner, TokenContractArtifact, [owner.getCompleteAddress(), 'TokenName', 'TKN', 18])
.send()
.deployed();
token = await TokenContract.deploy(owner, owner.getAddress(), 'TokenName', 'TKN', 18).send().deployed();

const initialBalance = 20n;
const initialBalance = 69;
const secret = Fr.random();
const secretHash = await computeSecretHash(secret);
const receipt = await token.methods.mint_private(initialBalance, secretHash).send().wait();

const storageSlot = token.artifact.storageLayout['pending_shields'].slot;
const noteTypeId = token.artifact.notes['TransparentNote'].id;
const note = new Note([new Fr(initialBalance), secretHash]);
const extendedNote = new ExtendedNote(
note,
owner.getAddress(),
token.address,
storageSlot,
noteTypeId,
TokenContract.storage.pending_shields.slot,
TokenContract.notes.TransparentNote.id,
receipt.txHash,
);
await pxe.addNote(extendedNote);
await pxe.addNote(extendedNote, owner.getAddress());

await token.methods.redeem_shield({ address: owner.getAddress() }, initialBalance, secret).send().wait();
await token.methods.redeem_shield(owner.getAddress(), initialBalance, secret).send().wait();
}, 120_000);
// docs:end:setup

// docs:start:test
it('increases recipient funds on transfer', async () => {
expect(await token.methods.balance_of_private(recipient.getAddress()).simulate()).toEqual(0n);
await token.methods.transfer(owner.getAddress(), recipient.getAddress(), 20n, 0).send().wait();
expect(await token.methods.balance_of_private(recipient.getAddress()).simulate()).toEqual(20n);
expect(await token.withWallet(recipient).methods.balance_of_private(recipient.getAddress()).simulate()).toEqual(0n);
await token.methods.transfer(recipient.getAddress(), 20).send().wait();
expect(await token.withWallet(recipient).methods.balance_of_private(recipient.getAddress()).simulate()).toEqual(
20n,
);
}, 30_000);
// docs:end:test
});
4 changes: 3 additions & 1 deletion yarn-project/pxe/src/database/kv_pxe_database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,9 @@ export class KVPxeDatabase implements PxeDatabase {
return true;
}

addCompleteAddress(completeAddress: CompleteAddress): Promise<boolean> {
async addCompleteAddress(completeAddress: CompleteAddress): Promise<boolean> {
await this.#addScope(completeAddress.address);

return this.#db.transaction(() => {
const addressString = completeAddress.address.toString();
const buffer = completeAddress.toBuffer();
Expand Down

0 comments on commit 48914ba

Please sign in to comment.