-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
62e1ace
commit 5dcc924
Showing
4 changed files
with
529 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import { describe, it, expect } from 'vitest'; | ||
import { | ||
Address, | ||
Hex, | ||
PrivateKeyAccount, | ||
TransactionSerializable, | ||
createPublicClient, | ||
http, | ||
zeroAddress, | ||
} from 'viem'; | ||
|
||
import { nitroTestnodeL2 } from './chains'; | ||
import { sequencerInboxActions } from './decorators/sequencerInboxActions'; | ||
import { | ||
createRollupHelper, | ||
getInformationFromTestnode, | ||
getNitroTestnodePrivateKeyAccounts, | ||
} from './testHelpers'; | ||
import { getKeysets } from './getKeysets'; | ||
|
||
const { l3SequencerInbox } = getInformationFromTestnode(); | ||
const { l3TokenBridgeDeployer, deployer } = getNitroTestnodePrivateKeyAccounts(); | ||
|
||
const client = createPublicClient({ | ||
chain: nitroTestnodeL2, | ||
transport: http(), | ||
}).extend( | ||
sequencerInboxActions({ | ||
sequencerInbox: l3SequencerInbox, | ||
}), | ||
); | ||
|
||
async function sendKeysetTransaction({ | ||
account, | ||
tx, | ||
}: { | ||
account: PrivateKeyAccount; | ||
tx: TransactionSerializable; | ||
}) { | ||
const txHash = await client.sendRawTransaction({ | ||
serializedTransaction: await account.signTransaction(tx), | ||
}); | ||
await client.waitForTransactionReceipt({ | ||
hash: txHash, | ||
}); | ||
} | ||
async function setValidKeyset({ | ||
keysetBytes, | ||
sequencerInbox, | ||
upgradeExecutor, | ||
account, | ||
}: { | ||
keysetBytes: Hex; | ||
sequencerInbox: Address; | ||
upgradeExecutor: Address; | ||
account: PrivateKeyAccount; | ||
}) { | ||
const tx = await client.sequencerInboxPrepareTransactionRequest({ | ||
functionName: 'setValidKeyset', | ||
args: [keysetBytes], | ||
account: account.address, | ||
upgradeExecutor, | ||
sequencerInbox, | ||
}); | ||
await sendKeysetTransaction({ account, tx }); | ||
} | ||
async function invalidateKeyset({ | ||
keysetHash, | ||
sequencerInbox, | ||
upgradeExecutor, | ||
account, | ||
}: { | ||
keysetHash: Hex; | ||
sequencerInbox: Address; | ||
upgradeExecutor: Address; | ||
account: PrivateKeyAccount; | ||
}) { | ||
const tx = await client.sequencerInboxPrepareTransactionRequest({ | ||
functionName: 'invalidateKeysetHash', | ||
args: [keysetHash], | ||
account: account.address, | ||
upgradeExecutor, | ||
sequencerInbox, | ||
}); | ||
await sendKeysetTransaction({ account, tx }); | ||
} | ||
|
||
// https://docs.arbitrum.io/launch-orbit-chain/concepts/anytrust-orbit-chain-keyset-generation#keyset-generation | ||
const keysetForZeroPK = | ||
'0x00000000000000010000000000000001012160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; | ||
const keysetHashForZeroPK = '0x4d795e20d33eea0b070600e4e100c512a750562bf03c300c99444bd5af92d9b0'; | ||
const keyset = | ||
'0x0000000000000002000000000000000801216006dcb5e56764bb72e6a45e6deb301ca85d8c4315c1da2efa29927f2ac8fb25571ce31d2d603735fe03196f6d56bcbf9a1999a89a74d5369822c4445d676c15ed52e5008daa775dc9a839c99ff963a19946ac740579874dac4f639907ae1bc69f0c6694955b524d718ca445831c5375393773401f33725a79661379dddabd5fff28619dc070befd9ed73d699e5c236c1a163be58ba81002b6130709bc064af5d7ba947130b72056bf17263800f1a3ab2269c6a510ef8e7412fd56d1ef1b916a1306e3b1d9c82c099371bd9861582acaada3a16e9dfee5d0ebce61096598a82f112d0a935e8cab5c48d82e3104b0c7ba79157dad1a019a3e7f6ad077b8e6308b116fec0f58239622463c3631fa01e2b4272409215b8009422c16715dbede5909060121600835f995f2478f24892d050daa289f8b6b9c1b185bcd28532f88d610c2642a2dc6f3509740236d33c3e2d9136aab17f819c8c671293bba277717762e8d1c1f7bac9e17dd28d2939a959bb38e500f9c11c38cebbc426e2dea97c40175a655d17400ae6c75ff49e884c79469249e70953258854b64fa8445c585ad45dc6dc6975501c6af7cff7074202c687f8a7bf1a3ac192689755f232275b4c8421b1a5669e9b904c29a292cdf961b783a7c0b4ce736900de4d8c63c5f85a65cb44af34bef840acef84ab75f44c4c9137610b68107aff3bbdcc19119c7a927c115b7b9bfb27d85c500ee77d13ec5a97a3ae6bf51d3b70a5502e8416de7b5eb8e9feee376411ca35c8a7f3f597c7606578cf96a4715ce5a35cf48e39c0a1faa2dee22d74e681901216005db98e51080bb392a7b5ebdbfcf33e0f4f0193102cc40f79a9ef0a9557c5a62dd1ef800056946e8329f979ba0cc82510d0dc78c3cceffa66ee5de5e298987a9858bf5262171614e556f40687ce6912cbea6a5b44472cb3ff107ece69cbd0fda0db392a64a82be714077351d6384d6cea254ad3c21e45a87852dac39190865c449a647a4e39928dad7611b0d2074437d17e44c766f3e0a150852cde235d455271b91eca03d7ec91c910ca38540f6f7ab94fcbfa4c43a4dd0f064b6210037d9370b3ad702eb883dcbf7ae6d8fe6529164594692f00f9888c2e77d135e922585ad9ce1c16291b9ab3e4a98582b3edd209a100a005fe44fa2e4843bf1995991a8bfb5af0fd2c5e5749a4a96d8865f31cefb9368f6feacb61f2477f24ad332b6553201216006ce839de4d6a3ae02f25b4089531e6a3d2de556bd006bd30cf2d3408b977d18f1756dd4a1bc3c00db9002f0d8ef1af50fbaa6959decbec1cbe234cc6ef6270a03339090e0238f8ac9f8a18f44b8734c8f3b6123dd128ae48a0863b9a7f6d88302043681772c2b79f350c14bc9d7b18e578c795ca76925ce7bd2891d09aa37fe2ce1ea2ffe4c038fef22f66e28995c61090221e86a3368fb6d671aafc19001f4227f92f3671af6a60b3db1285a142f49c1f450b76feb9b1aef1a551e858e4b7302c6cf1ca7fac05b993ba375d8183f90c089fa8a3df31a443d2e0a8ef193067068fbfcca2cef234cf6d9c9b5884ef69705a71810a56651726ca3b7acdfaffdfab9b2844b4ea6872b43ff9b7da2e10a2e23a79130c3c4c70a8ad0a77eb2d51f160121600f872b898a4fd1b8ae73515f7d33cd7be1e971ce1896aabef2f8926e586c4248dc0db7fd7851402c14149dc3dc84f3830c346167c39e5323971ac340415f0a2eb054a9a8e0a5d503a2acfecebdd1df71aeeac3b38260480c699bc09934f0913e0ee5aaeabd57313285207eb89366b411286cf3f1c5e30eb7e355f55385308b91d5807284323ee89a9743c70676f4949504ced3ed41612cbfda06ad55200c1c77d3fb3700059befd64c44bc4a57cb567ec1481ee564cf6cd6cf1f2f4a2dee6db00c547c38400ab118dedae8afd5bab93b703f76a0991baa5d43fbb125194c06b5461f8c738a3c4278a3d98e5456aec0720883c0d28919537a36e2ffd5f731e742b6653557d154c164e068ef983b367ef626faaed46f4eadecbb12b7e55f23175d01216002c2ec378eb6ba17a9e81b8fd44263d699c34719492a4ecf1ee76a942bc22478fb7a9f94e2f15822630f2d616c32a3340387118e4b96e26d6e41dbaab9fe27ad608bd823a142f988f7da999cdeca08ab4afedb6b3da2d4db208cc0ba91bfd44e153bd73736b7df01341780aaa7f185fca0d3a478dfb53b612ed91f054416de7bd62c59d39b4ee604ea96cb42f3d6aa20112197b4b9acf736e47fb44cf00cbe3725227d8aea5bca1efbbb894c1cbb566a7ab1b701e81dafd5b9f3077ce4f8b2f8000a047fb88dc5dcf8afee7658df0f985333a31516fba62200760fe4256c0260b199949737fb88f77d75c35dea4349261213ee6bebbff350204aff7cd8461651bed57cb455184b90abf56a1bb23deffea9bb25daec5cd2be9d7ce010719b9d5a012160137e0965267913f9eaf85bff22e3ce5f44bb1bfaed7679b1680acd15436a84325eba7f2962ca46937ccbf46d99edc944034cdd97bc4fb1d8dc3addb9c348431a99975959e6ac8238376af31f03e754fa3c315927cd6860265ec8e6e97da40a9509327773e7aa5bcfaef7690d769063336f6d5210a7de55e0ebf251ffd53f6dca022267fbc3ffc08e4709e3414a96b804056dd7e7ffc38927d8a3d8a5c0f46a8e737d638e89ef5c96fc5dfe79a21da0a2b5cbd0c1bb2e95ca9bbff1d416585c2c0119b676dc053c5abb3b0b4d60eafa065715a2c301a8d58bac871df836dfc0eb8d4ede191cab4cf6655451a37c9cf376082a65d5f23b818c185c56b16ce980b6fe0d68838fde6778fcc652cf6813fefd21db3727454df59ad3be7465d60507aa0121600478d126ce394ef52d6ffc6845672dfcedb14d4cabe76acd9efff25892b31dc32d8bd21426575f08a30b1b84bb8c1f6507810e25d47852f1f2a06b66b5341d02d7481a1cce01257e768aa1a59b683a28f6f7946674541f0f4e23643d31dfd7e90958a361c7db86b628fe075d94c85e2c43f858d3f3683d5369a87f76b3902c0765ddc8c904e375b0f5740db5d2e25f1b159a966e20596b1a38ff311b5365d7709cc679991307d692152cff49876663f315e081f4c0bc85c38a66f2198d5390170c275e23e9843ea74a046b3e7084aaa1d53c6fc6c8622250dcb812d444c341a8470df4b2c2ec3ab0d4aa563b101a31520d71df0c9c1eec4818cbaecb324ac2b9045aeb316bb1f4c6c9aac9247f1ec3fb824247f3858d1b9c6031413a11a7b059'; | ||
const keysetHash = '0xf8bb9a67839d1767e79afe52d21e97a04ee0bf5f816d5b52c10df60cccb7f822'; | ||
|
||
async function createAnytrustRollup() { | ||
const deployerAddress = deployer.address; | ||
const batchPoster = deployer.address; | ||
const validators: [Address] = [deployerAddress]; | ||
|
||
return createRollupHelper({ | ||
deployer: l3TokenBridgeDeployer, | ||
batchPoster, | ||
validators, | ||
nativeToken: zeroAddress, | ||
client, | ||
}); | ||
} | ||
|
||
// Tests can be enabled once we run one node per integration test | ||
describe.skip('successfully get valid keysets', () => { | ||
it('when disabling the same keyset multiple time', async () => { | ||
const { createRollupInformation } = await createAnytrustRollup(); | ||
const { sequencerInbox, upgradeExecutor, rollup } = createRollupInformation.coreContracts; | ||
const { keysets: initialKeysets } = await getKeysets(client, { | ||
sequencerInbox, | ||
}); | ||
|
||
// By default, chains from nitro testnode has no keyset | ||
expect(initialKeysets).toEqual({}); | ||
|
||
// Calling invalidateKeysetHash multiple time for the same keyset hash throws error | ||
// We need to call setValidKeyset first | ||
await setValidKeyset({ | ||
keysetBytes: keyset, | ||
sequencerInbox, | ||
upgradeExecutor, | ||
account: l3TokenBridgeDeployer, | ||
}); | ||
await invalidateKeyset({ | ||
keysetHash: keysetHash, | ||
sequencerInbox, | ||
upgradeExecutor, | ||
account: l3TokenBridgeDeployer, | ||
}); | ||
await setValidKeyset({ | ||
keysetBytes: keyset, | ||
sequencerInbox, | ||
upgradeExecutor, | ||
account: l3TokenBridgeDeployer, | ||
}); | ||
|
||
const { keysets } = await getKeysets(client, { | ||
sequencerInbox, | ||
}); | ||
|
||
expect(keysets).toEqual({ | ||
[keysetHash]: keyset, | ||
}); | ||
|
||
await invalidateKeyset({ | ||
keysetHash: keysetHash, | ||
sequencerInbox, | ||
upgradeExecutor, | ||
account: l3TokenBridgeDeployer, | ||
}); | ||
|
||
const { keysets: emptyKeysets } = await getKeysets(client, { | ||
sequencerInbox, | ||
}); | ||
|
||
expect(emptyKeysets).toEqual({}); | ||
|
||
await setValidKeyset({ | ||
keysetBytes: keysetForZeroPK, | ||
sequencerInbox, | ||
upgradeExecutor, | ||
account: l3TokenBridgeDeployer, | ||
}); | ||
|
||
const { keysets: finalKeysets } = await getKeysets(client, { | ||
sequencerInbox, | ||
}); | ||
|
||
expect(finalKeysets).toEqual({ | ||
[keysetHashForZeroPK]: keysetForZeroPK, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { Address, Chain, Hex, PublicClient, Transport, getAbiItem } from 'viem'; | ||
import { sequencerInboxABI } from './abi'; | ||
import { createRollupFetchTransactionHash } from './createRollupFetchTransactionHash'; | ||
|
||
const SetValidKeysetEventAbi = getAbiItem({ abi: sequencerInboxABI, name: 'SetValidKeyset' }); | ||
const InvalidateKeysetEventAbi = getAbiItem({ abi: sequencerInboxABI, name: 'InvalidateKeyset' }); | ||
|
||
export type GetKeysetsParams = { | ||
/** Address of the sequencerInbox we're getting logs from */ | ||
sequencerInbox: Address; | ||
}; | ||
export type GetKeysetsReturnType = { | ||
/** Map of keyset hash to keyset bytes | ||
* keyset hash are used to invalidate a given keyset | ||
*/ | ||
keysets: { | ||
[keysetHash: Hex]: Hex; | ||
}; | ||
}; | ||
|
||
/** | ||
* | ||
* @param {PublicClient} publicClient - The chain Viem Public Client | ||
* @param {GetKeysetsParams} GetKeysetsParams {@link GetKeysetsParams} | ||
* | ||
* @returns Promise<{@link GetKeysetsReturnType}> | ||
* | ||
* @example | ||
* const { keysets } = getKeysets(client, { | ||
* sequencerInbox: '0x211E1c4c7f1bF5351Ac850Ed10FD68CFfCF6c21b' | ||
* }); | ||
* | ||
*/ | ||
export async function getKeysets<TChain extends Chain | undefined>( | ||
publicClient: PublicClient<Transport, TChain>, | ||
{ sequencerInbox }: GetKeysetsParams, | ||
): Promise<GetKeysetsReturnType> { | ||
let blockNumber: bigint | 'earliest'; | ||
let createRollupTransactionHash: Address | null = null; | ||
const rollup = await publicClient.readContract({ | ||
functionName: 'rollup', | ||
address: sequencerInbox, | ||
abi: sequencerInboxABI, | ||
}); | ||
try { | ||
createRollupTransactionHash = await createRollupFetchTransactionHash({ | ||
rollup, | ||
publicClient, | ||
}); | ||
const receipt = await publicClient.waitForTransactionReceipt({ | ||
hash: createRollupTransactionHash, | ||
}); | ||
blockNumber = receipt.blockNumber; | ||
} catch (e) { | ||
console.warn(`[getKeysets] ${(e as any).message}`); | ||
blockNumber = 'earliest'; | ||
} | ||
|
||
const events = await publicClient.getLogs({ | ||
address: sequencerInbox, | ||
events: [SetValidKeysetEventAbi, InvalidateKeysetEventAbi], | ||
fromBlock: blockNumber, | ||
toBlock: 'latest', | ||
}); | ||
|
||
const keysets = events.reduce((acc, event) => { | ||
switch (event.eventName) { | ||
case SetValidKeysetEventAbi.name: { | ||
const { keysetHash, keysetBytes } = event.args; | ||
if (!keysetHash || !keysetBytes) { | ||
console.warn(`[getKeysets] Missing args for event: ${event.transactionHash}`); | ||
return acc; | ||
} | ||
acc.set(keysetHash, keysetBytes); | ||
return acc; | ||
} | ||
case InvalidateKeysetEventAbi.name: { | ||
const { keysetHash } = event.args; | ||
if (!keysetHash) { | ||
console.warn(`[getKeysets] Missing args for event: ${event.transactionHash}`); | ||
return acc; | ||
} | ||
acc.delete(keysetHash); | ||
return acc; | ||
} | ||
} | ||
}, new Map<Hex, Hex>()); | ||
|
||
return { | ||
keysets: Object.fromEntries(keysets), | ||
}; | ||
} |
Oops, something went wrong.