Skip to content

Commit

Permalink
fix: replace force insert in TS (#643)
Browse files Browse the repository at this point in the history
* fix: replace force insert in TS

* fix: remove force inclusion sol

* fix: remove temp `return`

* fix: address comments
  • Loading branch information
LHerskind authored May 23, 2023
1 parent 0997392 commit a0f95f4
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 79 deletions.
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
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',
);

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

0 comments on commit a0f95f4

Please sign in to comment.