Skip to content
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
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ From root directory:
yarn install
```

## Environment Setup

To simplify providing environment variables across all tutorials, a helper script automates creating `.env` files from each existing `.env-sample`.

```bash
yarn setup-envs

# To update existing .env files as well
yarn setup-envs --update
```

## Testing

1. Start the nitro-testnode (you can find instructions [here](https://docs.arbitrum.io/run-arbitrum-node/run-local-full-chain-simulation)) with the following parameters:
Expand All @@ -26,6 +37,10 @@ yarn install
yarn run testAll
```

### Notes on RPCs and Finality

Using public testnet RPCs can be slow because many tutorials wait for transaction finality or multiple confirmations. Some tests may take 10–15 minutes to complete on testnets. For faster and more reliable execution, prefer running a local node and pointing your environment variables (`CHAIN_RPC`, `PARENT_CHAIN_RPC`, and `L1_RPC` when applicable) to local RPC endpoints.

## What's included?

#### :white_check_mark: Basics
Expand Down
40 changes: 20 additions & 20 deletions customNetwork.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
"chainID": 412346,
"confirmPeriodBlocks": 20,
"ethBridge": {
"bridge": "0x5eCF728ffC5C5E802091875f96281B5aeECf6C49",
"inbox": "0x9f8c1c641336A371031499e3c362e40d58d0f254",
"outbox": "0x50143333b44Ea46255BEb67255C9Afd35551072F",
"rollup": "0xe5Ab92C74CD297F0a1F2914cE37204FC5Bc4e82D",
"sequencerInbox": "0x18d19C5d3E685f5be5b9C86E097f0E439285D216"
"bridge": "0xd21d0cA137A64165E3C3702a37C5D42E6a5CdACC",
"inbox": "0xF52c6E85A9E6287942fD913DfCc269EB571816a6",
"outbox": "0xbf2265Cd6Fd551e5EAA862Fd81BA317D585eE693",
"rollup": "0x1b172F52EC0EFFeeC7946903F20410B5d6571AA0",
"sequencerInbox": "0x7F6958d308593dC0BdEa73c4bcD742965E1C79af"
},
"explorerUrl": "",
"isArbitrum": true,
Expand All @@ -19,17 +19,17 @@
"nitroGenesisL1Block": 0,
"depositTimeout": 900000,
"tokenBridge": {
"parentGatewayRouter": "0x093AAa96CD4387A68FC0e24C60140938Dc812549",
"parentGatewayRouter": "0x145899e2EF2A3f460Cfb2F7897615F5758000F66",
"childGatewayRouter": "0x32656396981868E925280FB772b3f806892cf4bF",
"parentErc20Gateway": "0x00D9fE1a2B67B8151aEdE8855c95E58D73FB4245",
"parentErc20Gateway": "0x4D9Aa26aCee73293ba84fB1FcA8100006239860E",
"childErc20Gateway": "0x7424e3DAAAAcd867c85ceB75c1E00119F2ee5eb7",
"parentCustomGateway": "0x8407E6180dC009D20D26D4BABB4790C1d4E6D2aA",
"parentCustomGateway": "0xC9ba2864E0E5dC3B78a539fA5e50b4508595A236",
"childCustomGateway": "0x0B35cfE62314C3852A0942b5830c728353BD654F",
"parentWethGateway": "0xB8F48Ba39fCfB44d70F6008fe1bf4F3E744044AF",
"parentWethGateway": "0xCb24A87c3Dfc5b6DC8f1Da8D62D731fA1109A32C",
"childWethGateway": "0x67aE8014BD1A0c1Ed747715d22b3b3a188aC324B",
"parentWeth": "0x7E32b54800705876d3b5cFbc7d9c226a211F7C1a",
"childWeth": "0xA1abD387192e3bb4e84D3109181F9f005aBaF5CA",
"parentProxyAdmin": "0x2A1f38c9097e7883570e0b02BFBE6869Cc25d8a3",
"parentProxyAdmin": "0x275FC51309e5928Cb085b463ADEF5cbD45c76b62",
"childProxyAdmin": "0x9F95547ABB0FfC92b4E37b3124d1e8613d5aB74A",
"parentMultiCall": "0x49117fC32930E324F2E9A7BeA588FFb26008b8eC",
"childMultiCall": "0x6B1E93aE298B64e8f5b9f43B65Dd8F1eaA6DD4c3"
Expand All @@ -41,11 +41,11 @@
"chainID": 333333,
"confirmPeriodBlocks": 20,
"ethBridge": {
"bridge": "0xA584795e24628D9c067A6480b033C9E96281fcA3",
"inbox": "0xDcA690902d3154886Ec259308258D10EA5450996",
"outbox": "0xda243bD61B011024FC923164db75Dde198AC6175",
"rollup": "0x47b238E195b638b8972Cb3649e5d6775c279245d",
"sequencerInbox": "0x16c54EE2015CD824415c2077F4103f444E00A8cb"
"bridge": "0xFbd865f29BadF3fdcf14b7e742F78c8DdF7fa4C9",
"inbox": "0x7CB5a1892d31936a13CeE3a4A8183Ed40300e87c",
"outbox": "0x3dAEcE87269310A2f055920ef5C84679ca50F218",
"rollup": "0x9129f7A7f4D5A87F971Fe15C554AD1CF22ceb4EF",
"sequencerInbox": "0x99c807B58c00DE2b068e521AAC227A1e8ADe1fa9"
},
"explorerUrl": "",
"isArbitrum": true,
Expand All @@ -57,17 +57,17 @@
"nitroGenesisL1Block": 0,
"depositTimeout": 900000,
"tokenBridge": {
"parentGatewayRouter": "0xfE03DBdf7A126994dBd749631D7fbaB58C618c58",
"parentGatewayRouter": "0x9a6E8E638451781B47b8632a11E56020270A335B",
"childGatewayRouter": "0x8B6BC759226f8Fe687c8aD8Cc0DbF85E095e9297",
"parentErc20Gateway": "0x6B0805Fc6e275ef66a0901D0CE68805631E271e5",
"parentErc20Gateway": "0x7A6b9Ca6e4f87E6a641c1AbD7671aD42bF538977",
"childErc20Gateway": "0xaa7d51aFFEeB32d99b1CB2fd6d81D7adA4a896e8",
"parentCustomGateway": "0xA191D519260A06b32f8D04c84b9F457B8Caa0514",
"parentCustomGateway": "0xDCa39C8Fbd686cb8838106Ed94C0B9e9802697d6",
"childCustomGateway": "0xD4816AeF8f85A3C1E01Cd071a81daD4fa941625f",
"parentWethGateway": "0x77603b0ea6a797C74Fa9ef11b5BdE04A4E03D550",
"parentWethGateway": "0x3bF927fc03d13bD2199b02a029ABb490D13706b3",
"childWethGateway": "0xA6AB233B3c7bfd0399834897b5073974A3D467e2",
"parentWeth": "0xA1abD387192e3bb4e84D3109181F9f005aBaF5CA",
"childWeth": "0x582a8dBc77f665dF2c49Ce0a138978e9267dd968",
"parentProxyAdmin": "0x1A61102c26ad3f64bA715B444C93388491fd8E68",
"parentProxyAdmin": "0x74513d47D265527f0647eD5B90072578c609B378",
"childProxyAdmin": "0x36C56eC2CF3a3f53db9F01d0A5Ae84b36fb0A1e2",
"parentMultiCall": "0x20a3627Dcc53756E38aE3F92717DE9B23617b422",
"childMultiCall": "0x052B15c8Ff0544287AE689C4F2FC53A3905d7Db3"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"lint": "eslint .",
"prettier:format": "prettier './**/*.{js,json,md,sol,ts,yml}' --write && yarn run lint --fix",
"prettier:check": "prettier './**/*.{js,json,md,sol,ts,yml}' --check && yarn run lint",
"testAll": "tests/runAll.sh"
"testAll": "tests/runAll.sh",
"setup-envs": "node scripts/setup-envs.js"
},
"devDependencies": {
"@offchainlabs/eslint-config-typescript": "^0.2.1",
Expand Down
9 changes: 6 additions & 3 deletions packages/arb-shared-dependencies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,21 @@ const requireEnvVariables = (envVars) => {
console.log('Environmental variables properly set 👍');
};

const addCustomNetworkFromFile = () => {
const addCustomNetworkFromFile = (registerFn) => {
const pathToCustomNetworkFile = path.join(__dirname, '..', '..', 'customNetwork.json');
if (!fs.existsSync(pathToCustomNetworkFile)) {
return;
}

// Use the provided register function, or fall back to the local one
const register = registerFn || registerCustomArbitrumNetwork;

const customNetworkFileContents = fs.readFileSync(pathToCustomNetworkFile, 'utf8');
const customNetworkInformation = JSON.parse(customNetworkFileContents);
if (customNetworkInformation instanceof Array) {
customNetworkInformation.map((customNetwork) => registerCustomArbitrumNetwork(customNetwork));
customNetworkInformation.map((customNetwork) => register(customNetwork));
} else {
registerCustomArbitrumNetwork(customNetworkInformation);
register(customNetworkInformation);
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Block verification in an assertion posted on the parent chain

This tutorial shows how to verify whether a block of a chain has been processed as part of an RBlock assertion on its parent chain.
This tutorial shows how to verify whether a block of a chain has been processed as part of an assertion on its parent chain.

It uses the `Rollup` contract to find the latest confirmed (or created if configured in the script) RBlock/node, find the event that created it, and get the latest processed block hash of the child chain that's part of the assertion of that RBlock/node.
It uses the `Rollup` contract to find the latest confirmed assertion hash, find the `AssertionCreated` event that created it, and get the latest processed block hash of the child chain that's part of that assertion's `afterState`.

Then it checks whether the block number passed as argument was created before the latest block hash of the child chain processed.

See [./exec.js](./scripts/exec.js) for inline explanations.
See [./exec.ts](./scripts/exec.ts) for inline explanations.

## Set environment variables

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { providers, Contract } from 'ethers';
import { getArbitrumNetwork } from '@arbitrum/sdk';
import { RollupCore__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupCore__factory';
import { getArbitrumNetwork, registerCustomArbitrumNetwork } from '@arbitrum/sdk';
import { BoldRollupUserLogic__factory } from '@arbitrum/sdk/dist/lib/abi-bold/factories/BoldRollupUserLogic__factory';
import { arbLog, requireEnvVariables, addCustomNetworkFromFile } from 'arb-shared-dependencies';
require('dotenv').config();
requireEnvVariables(['CHAIN_RPC', 'PARENT_CHAIN_RPC']);
Expand All @@ -11,93 +11,64 @@ requireEnvVariables(['CHAIN_RPC', 'PARENT_CHAIN_RPC']);
const parentChainProvider = new providers.JsonRpcProvider(process.env.PARENT_CHAIN_RPC);
const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC);

/**
* Use the latest node created instead of the last confirmed one
*/
const useCreatedNodeInsteadOfConfirmed = false;

const main = async (childChainBlockNumberToVerify: number) => {
await arbLog(
'Find whether a block of the child chain has been processed as part of an RBlock on the parent chain',
);

/**
* Add the custom network configuration to the SDK if present
*/
addCustomNetworkFromFile();
addCustomNetworkFromFile(registerCustomArbitrumNetwork);

/**
* Use childChainNetwork to find the Rollup contract's address and instantiate a contract handler
*/
const childChainNetwork = await getArbitrumNetwork(childChainProvider);
const rollupAddress = childChainNetwork.ethBridge.rollup;
const rollup = new Contract(rollupAddress, RollupCore__factory.abi, parentChainProvider);
const rollup = new Contract(rollupAddress, BoldRollupUserLogic__factory.abi, parentChainProvider);
console.log(`Rollup contract found at address ${rollup.address}`);

/**
* Get the latest node created or confirmed
*/
const nodeId = useCreatedNodeInsteadOfConfirmed
? await rollup.latestNodeCreated()
: await rollup.latestConfirmed();
console.log(
`Latest ${useCreatedNodeInsteadOfConfirmed ? 'created' : 'confirmed'} Rblock/node: ${nodeId}`,
);
const assertionHash: string = await rollup.latestConfirmed();
console.log(`Latest confirmed assertion hash: ${assertionHash}`);

/**
* Find the NodeCreated event
*/
const nodeCreatedEventFilter = rollup.filters.NodeCreated(nodeId);
const nodeCreatedEvents = await rollup.queryFilter(nodeCreatedEventFilter);
if (!nodeCreatedEvents) {
throw new Error(`INTERNAL ERROR: NodeCreated events not found for Rblock/node: ${nodeId}`);
const assertionCreatedEventFilter = (rollup as any).filters.AssertionCreated(assertionHash);
const assertionCreatedEvents = await rollup.queryFilter(assertionCreatedEventFilter);
if (!assertionCreatedEvents || assertionCreatedEvents.length === 0) {
throw new Error(
`INTERNAL ERROR: AssertionCreated events not found for assertion: ${assertionHash}`,
);
}
const nodeCreatedEvent = nodeCreatedEvents[0];
console.log(`NodeCreated event found in transaction ${nodeCreatedEvent.transactionHash}`);
const assertionCreatedEvent = assertionCreatedEvents[0];
console.log(
`AssertionCreated event found in transaction ${assertionCreatedEvent.transactionHash}`,
);

/**
* Finding the assertion within the NodeCreated event, and getting the afterState
*/
if (!nodeCreatedEvent.args) {
if (!assertionCreatedEvent.args) {
throw new Error(
`INTERNAL ERROR: NodeCreated event does not have an assertion for Rblock/node: ${nodeId}`,
`INTERNAL ERROR: AssertionCreated event does not have an assertion for hash: ${assertionHash}`,
);
}
const assertion = nodeCreatedEvent.args.assertion;
const assertion = (assertionCreatedEvent as any).args.assertion;
const afterState = assertion.afterState;

/**
* Latest child chain's block hash processed is in the first element of the bytes32Vals property in the globalState
*/
// Latest child chain's block hash processed is in the first element of the bytes32Vals property in the globalState
const lastChildChainBlockHash = afterState.globalState.bytes32Vals[0];
console.log(
`Last block hash of the child chain processed in this Rblock/node: ${lastChildChainBlockHash}`,
);

/**
* Getting the block number from that block hash
*/
// Getting the block number from that block hash

const lastChildChainBlock = await childChainProvider.getBlock(lastChildChainBlockHash);
const lastChildChainBlockNumber = lastChildChainBlock.number;
console.log(
`Last block number of the child chain processed in this Rblock/node: ${lastChildChainBlockNumber}`,
);

/**
* Final verification
*/
// Final verification
console.log(`************`);
if (lastChildChainBlockNumber > childChainBlockNumberToVerify) {
console.log(
`${childChainBlockNumberToVerify} has been processed as part of the latest ${
useCreatedNodeInsteadOfConfirmed ? 'created' : 'confirmed'
} RBlock/node`,
`${childChainBlockNumberToVerify} has been processed as part of the latest confirmed assertion`,
);
} else {
console.log(
`${childChainBlockNumberToVerify} has NOT been processed as part of the latest ${
useCreatedNodeInsteadOfConfirmed ? 'created' : 'confirmed'
} RBlock/node`,
`${childChainBlockNumberToVerify} has NOT been processed as part of the latest confirmed assertion`,
);
}
console.log(`************`);
Expand All @@ -106,9 +77,7 @@ const main = async (childChainBlockNumberToVerify: number) => {
// Getting the transaction hash from the command arguments
if (process.argv.length < 3) {
console.log(
`Missing block number of the child chain to verify whether it has been processed in the latest ${
useCreatedNodeInsteadOfConfirmed ? 'created' : 'confirmed'
} RBlock/node`,
'Missing block number of the child chain to verify whether it has been processed in the latest confirmed assertion',
);
console.log(`Usage: yarn run exec <block number>`);
process.exit(1);
Expand Down
Loading
Loading