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

fix: replace force insert in TS #643

Merged
merged 4 commits into from
May 23, 2023
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
3 changes: 0 additions & 3 deletions l1-contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ remappings = [

# See more config options https://github.com/foundry-rs/foundry/tree/master/config

# Set chain_id to one for messaging tests
chain_id = 1

[fmt]
line_length = 100
tab_width = 2
Expand Down
47 changes: 41 additions & 6 deletions l1-contracts/test/Decoder.t.sol

Large diffs are not rendered by default.

27 changes: 3 additions & 24 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,6 @@ import {Rollup} from "@aztec/core/Rollup.sol";
* Main use of these test is shorter cycles when updating the decoder contract.
*/
contract RollupTest is DecoderTest {
Registry internal registry;
Inbox internal inbox;
Outbox internal outbox;
Rollup internal rollup;

function setUp() public override(DecoderTest) {
super.setUp();
registry = new Registry();
inbox = new Inbox(address(registry));
outbox = new Outbox(address(registry));
rollup = new Rollup(registry);

registry.upgrade(address(rollup), address(inbox), address(outbox));
}

function testEmptyBlock() public override(DecoderTest) {
(,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) =
helper.decode(block_empty_1);
Expand Down Expand Up @@ -64,8 +49,9 @@ contract RollupTest is DecoderTest {
(,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) =
helper.decode(block_mixed_1);

bytes32[] memory expectedL1ToL2Msgs = _populateInbox();

for (uint256 i = 0; i < l1ToL2Msgs.length; i++) {
_insertInboxEntry(l1ToL2Msgs[i]);
assertTrue(inbox.contains(l1ToL2Msgs[i]), "msg not in inbox");
}

Expand All @@ -86,17 +72,10 @@ contract RollupTest is DecoderTest {
}

for (uint256 i = 0; i < l1ToL2Msgs.length; i++) {
assertEq(l1ToL2Msgs[i], bytes32(uint256(0x401 + i)), "Invalid l1ToL2Msgs");
assertEq(l1ToL2Msgs[i], expectedL1ToL2Msgs[i], "Invalid l1ToL2Msgs");
assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg not consumed");
}

assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash");
}

function _insertInboxEntry(bytes32 _entryHash) internal {
// Compute where exactly we need to shove the entry
bytes32 slot = keccak256(abi.encodePacked(_entryHash, uint256(0)));
uint256 value = uint256(1) | uint256(type(uint32).max) << 128;
vm.store(address(inbox), slot, bytes32(value));
}
}
28 changes: 19 additions & 9 deletions l1-contracts/test/portals/RNA.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {Outbox} from "@aztec/core/messagebridge/Outbox.sol";
import {Inbox} from "@aztec/core/messagebridge/Inbox.sol";
import {Registry} from "@aztec/core/messagebridge/Registry.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {Hash} from "@aztec/core/libraries/Hash.sol";
import {RollupNativeAsset} from "./RollupNativeAsset.sol";

contract RNATest is Test {
Expand All @@ -24,9 +26,7 @@ contract RNATest is Test {
// Using a run of e2e_rollup_native_asset_contract.test.ts to get values
// for entryKeys and aztecAddress
bytes32 internal constant AZTEC_ADDRESS =
0x06b5fb872b0b08560791085e14039c2c23c3ba6591cc21ae067cd9036461d032;
bytes32 internal constant ENTRY_KEY =
0x1aa9c93cf0144c36f3242e9983e11eb153bbc401340c8777e49e28093ac88b86;
0x1647b194c649f5dd01d7c832f89b0f496043c9150797923ea89e93d5ac619a93;

function setUp() public {
registry = new Registry();
Expand All @@ -45,23 +45,33 @@ contract RNATest is Test {
}

function testWithdraw() public {
uint256 withdrawAmount = 654;
address _recipient = address(0xdead);
bytes32[] memory entryKeys = new bytes32[](1);
entryKeys[0] = ENTRY_KEY;
entryKeys[0] = outbox.computeEntryKey(
DataStructures.L2ToL1Msg({
sender: DataStructures.L2Actor({actor: AZTEC_ADDRESS, version: 1}),
recipient: DataStructures.L1Actor({actor: address(rna), chainId: block.chainid}),
content: Hash.sha256ToField(
abi.encodeWithSignature("withdraw(uint256,address)", withdrawAmount, _recipient)
)
})
);

// Insert messages into the outbox (impersonating the rollup contract)
vm.prank(address(rollup));
outbox.sendL1Messages(entryKeys);

assertEq(rna.balanceOf(address(0xdead)), 0);
assertEq(rna.balanceOf(_recipient), 0);

vm.expectEmit(true, true, true, true);
emit MessageConsumed(ENTRY_KEY, address(rna));
bytes32 entryKey = rna.withdraw(654, address(0xdead));
emit MessageConsumed(entryKeys[0], address(rna));
bytes32 entryKey = rna.withdraw(withdrawAmount, _recipient);
// Should have received 654 RNA tokens
assertEq(rna.balanceOf(address(0xdead)), 654);
assertEq(rna.balanceOf(_recipient), withdrawAmount);

// Should not be able to withdraw again
vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKey));
rna.withdraw(654, address(0xdead));
rna.withdraw(withdrawAmount, _recipient);
}
}
2 changes: 1 addition & 1 deletion l1-contracts/test/portals/TokenPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ contract TokenPortalTest is Test {

// Check for the expected message
DataStructures.L1ToL2Msg memory expectedMessage = DataStructures.L1ToL2Msg({
sender: DataStructures.L1Actor(address(tokenPortal), 1),
sender: DataStructures.L1Actor(address(tokenPortal), block.chainid),
recipient: DataStructures.L2Actor(l2TokenAddress, 1),
content: Hash.sha256ToField(abi.encodeWithSignature("mint(uint256,bytes32)", amount, to)),
secretHash: secretHash,
Expand Down
118 changes: 88 additions & 30 deletions yarn-project/end-to-end/src/integration_l1_publisher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
KERNEL_PUBLIC_DATA_UPDATE_REQUESTS_LENGTH,
range,
makeTuple,
AztecAddress,
} from '@aztec/circuits.js';
import { fr, makeNewContractData, makeProof } from '@aztec/circuits.js/factories';
import { createDebugLogger } from '@aztec/foundation/log';
Expand All @@ -36,17 +37,15 @@ import {
GetContractReturnType,
HttpTransport,
PublicClient,
createPublicClient,
WalletClient,
encodeFunctionData,
getAbiItem,
getAddress,
getContract,
http,
keccak256,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { foundry } from 'viem/chains';
import { PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts';
import { deployL1Contracts } from './deploy_l1_contracts.js';
import { L2Actor } from '@aztec/types';

// Accounts 4 and 5 of Anvil default startup with mnemonic: 'test test test test test test test test test test test junk'
const sequencerPK = '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a';
Expand All @@ -60,6 +59,7 @@ const numberOfConsecutiveBlocks = 2;

describe('L1Publisher integration', () => {
let publicClient: PublicClient<HttpTransport, Chain>;
let deployerAccount: PrivateKeyAccount;

let rollupAddress: Address;
let inboxAddress: Address;
Expand All @@ -68,7 +68,11 @@ describe('L1Publisher integration', () => {
let decoderHelperAddress: Address;

let rollup: GetContractReturnType<typeof RollupAbi, PublicClient<HttpTransport, Chain>>;
let inbox: GetContractReturnType<typeof InboxAbi, PublicClient<HttpTransport, Chain>>;
let inbox: GetContractReturnType<
typeof InboxAbi,
PublicClient<HttpTransport, Chain>,
WalletClient<HttpTransport, Chain>
>;
let outbox: GetContractReturnType<typeof OutboxAbi, PublicClient<HttpTransport, Chain>>;
let decoderHelper: GetContractReturnType<typeof DecoderHelperAbi, PublicClient<HttpTransport, Chain>>;

Expand All @@ -79,26 +83,24 @@ describe('L1Publisher integration', () => {
let builderDb: MerkleTreeOperations;

beforeEach(async () => {
const deployerAccount = privateKeyToAccount(deployerPK);
deployerAccount = privateKeyToAccount(deployerPK);
const {
rollupAddress: rollupAddress_,
inboxAddress: inboxAddress_,
outboxAddress: outboxAddress_,
unverifiedDataEmitterAddress: unverifiedDataEmitterAddress_,
decoderHelperAddress: decoderHelperAddress_,
publicClient: publicClient_,
walletClient,
} = await deployL1Contracts(config.rpcUrl, deployerAccount, logger, true);
publicClient = publicClient_;

rollupAddress = getAddress(rollupAddress_.toString());
inboxAddress = getAddress(inboxAddress_.toString());
outboxAddress = getAddress(outboxAddress_.toString());
unverifiedDataEmitterAddress = getAddress(unverifiedDataEmitterAddress_.toString());
decoderHelperAddress = getAddress(decoderHelperAddress_!.toString());

publicClient = createPublicClient({
chain: foundry,
transport: http(config.rpcUrl),
});

// Set up contract instances
rollup = getContract({
address: rollupAddress,
Expand All @@ -109,6 +111,7 @@ describe('L1Publisher integration', () => {
address: inboxAddress,
abi: InboxAbi,
publicClient,
walletClient,
});
outbox = getContract({
address: outboxAddress,
Expand Down Expand Up @@ -166,29 +169,84 @@ describe('L1Publisher integration', () => {
return tx;
};

const forceInsertionInInbox = async (l1ToL2Messages: Fr[]) => {
for (let i = 0; i < l1ToL2Messages.length; i++) {
const slot = keccak256(Buffer.concat([l1ToL2Messages[i].toBuffer(), fr(0).toBuffer()]));
const value = 1n | ((2n ** 32n - 1n) << 128n);
// we are using Fr for the value as an easy way to get a correctly sized buffer and string.
const params = `["${inboxAddress}", "${slot}", "0x${new Fr(value).toBuffer().toString('hex')}"]`;
await fetch(config.rpcUrl, {
body: `{"jsonrpc":"2.0", "method": "anvil_setStorageAt", "params": ${params}, "id": 1}`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
}
const sendToL2 = async (content: Fr, recipientAddress: AztecAddress) => {
// @todo @LHerskind version hardcoded here
LHerskind marked this conversation as resolved.
Show resolved Hide resolved
const recipient = new L2Actor(recipientAddress, 1);
// Note: using max deadline
const deadline = 2 ** 32 - 1;
// getting the 32 byte hex string representation of the content
const contentString = content.toString(true);
// Using the 0 value for the secretHash.
const emptySecretHash = Fr.ZERO.toString(true);

await inbox.write.sendL2Message(
[
{ actor: recipient.recipient.toString(), version: BigInt(recipient.version) },
deadline,
contentString,
emptySecretHash,
],
{} as any,
);

const entry = await inbox.read.computeEntryKey([
{
sender: {
actor: deployerAccount.address,
chainId: BigInt(publicClient.chain.id),
},
recipient: {
actor: recipientAddress.toString(),
version: 1n,
},
content: contentString,
secretHash: emptySecretHash,
deadline,
fee: 0n,
},
]);
return Fr.fromString(entry);
};

it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => {
const stateInRollup_ = await rollup.read.rollupStateHash();
expect(hexStringToBuffer(stateInRollup_.toString())).toEqual(Buffer.alloc(32, 0));

const blockNumber = await publicClient.getBlockNumber();
// random recipient address, just kept consistent for easy testing ts/sol.
const recipientAddress = AztecAddress.fromString(
'0x1647b194c649f5dd01d7c832f89b0f496043c9150797923ea89e93d5ac619a93',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this from? maybe leave a comment?

);

for (let i = 0; i < numberOfConsecutiveBlocks; i++) {
const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 128 * i + 1 + 0x400).map(fr);
await forceInsertionInInbox(l1ToL2Messages);
const l1ToL2Content = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 128 * i + 1 + 0x400).map(fr);
const l1ToL2Messages: Fr[] = [];

for (let j = 0; j < l1ToL2Content.length; j++) {
l1ToL2Messages.push(await sendToL2(l1ToL2Content[j], recipientAddress));
}

// check logs
const inboxLogs = await publicClient.getLogs({
address: inboxAddress,
event: getAbiItem({
abi: InboxAbi,
name: 'MessageAdded',
}),
fromBlock: blockNumber + 1n,
});
expect(inboxLogs).toHaveLength(l1ToL2Messages.length * (i + 1));
for (let j = 0; j < NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP; j++) {
const event = inboxLogs[j + i * NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP].args;
expect(event.content).toEqual(l1ToL2Content[j].toString(true));
expect(event.deadline).toEqual(2 ** 32 - 1);
expect(event.entryKey).toEqual(l1ToL2Messages[j].toString(true));
expect(event.fee).toEqual(0n);
expect(event.recipient).toEqual(recipientAddress.toString());
expect(event.recipientVersion).toEqual(1n);
expect(event.senderChainId).toEqual(BigInt(publicClient.chain.id));
expect(event.sender).toEqual(deployerAccount.address);
}

const txs = [
await makeBloatedProcessedTx(128 * i + 32),
Expand All @@ -201,12 +259,12 @@ describe('L1Publisher integration', () => {
// check that values are in the inbox
for (let j = 0; j < l1ToL2Messages.length; j++) {
if (l1ToL2Messages[j].isZero()) continue;
expect(await inbox.read.contains([`0x${l1ToL2Messages[j].toBuffer().toString('hex')}`])).toBeTruthy();
expect(await inbox.read.contains([l1ToL2Messages[j].toString(true)])).toBeTruthy();
}

// check that values are not in the outbox
for (let j = 0; j < block.newL2ToL1Msgs.length; j++) {
expect(await outbox.read.contains([`0x${block.newL2ToL1Msgs[j].toBuffer().toString('hex')}`])).toBeFalsy();
expect(await outbox.read.contains([block.newL2ToL1Msgs[j].toString(true)])).toBeFalsy();
}

/*// Useful for sol tests block generation
Expand Down Expand Up @@ -258,11 +316,11 @@ describe('L1Publisher integration', () => {
// check that values have been consumed from the inbox
for (let j = 0; j < l1ToL2Messages.length; j++) {
if (l1ToL2Messages[j].isZero()) continue;
expect(await inbox.read.contains([`0x${l1ToL2Messages[j].toBuffer().toString('hex')}`])).toBeFalsy();
expect(await inbox.read.contains([l1ToL2Messages[j].toString(true)])).toBeFalsy();
}
// check that values are inserted into the outbox
for (let j = 0; j < block.newL2ToL1Msgs.length; j++) {
expect(await outbox.read.contains([`0x${block.newL2ToL1Msgs[j].toBuffer().toString('hex')}`])).toBeTruthy();
expect(await outbox.read.contains([block.newL2ToL1Msgs[j].toString(true)])).toBeTruthy();
}
}
}, 60_000);
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/foundation/src/aztec-address/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ export class AztecAddress {
*
* @returns A hexadecimal string representation of the AztecAddress.
*/
toString() {
return '0x' + this.buffer.toString('hex');
toString(): `0x${string}` {
return `0x${this.buffer.toString('hex')}`;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@ describe('bigint-buffer', () => {
it('pads zero to even length', () => {
expect(toHex(0n)).toEqual('0x00');
});

it('pads zero to 32 bytes', () => {
expect(toHex(0n, true)).toEqual('0x0000000000000000000000000000000000000000000000000000000000000000');
});
});
});
5 changes: 3 additions & 2 deletions yarn-project/foundation/src/bigint-buffer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ export function toBufferBE(num: bigint, width: number): Buffer {
/**
* Converts a BigInt to its hex representation.
* @param num - The BigInt to convert.
* @param padTo32 - Whether to pad the resulting string to 32 bytes.
* @returns An even-length 0x-prefixed string.
*/
export function toHex(num: bigint): `0x${string}` {
export function toHex(num: bigint, padTo32 = false): `0x${string}` {
const str = num.toString(16);
const targetLen = str.length % 2 === 0 ? str.length : str.length + 1;
const paddedStr = str.padStart(targetLen, '0');
const paddedStr = str.padStart(padTo32 ? 64 : targetLen, '0');
return `0x${paddedStr}`;
}
5 changes: 3 additions & 2 deletions yarn-project/foundation/src/fields/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ export class Fr {
* The resulting string is prefixed with '0x' and represents the bigint value
* in base 16.
*
* @param padTo32 - Whether to pad the string to 32 bytes.
* @returns A hex-encoded string representing the value of the class instance.
*/
toString(): `0x${string}` {
return toHex(this.value);
toString(padTo32 = false): `0x${string}` {
return toHex(this.value, padTo32);
}

/**
Expand Down