/* This file is part of web3.js. web3.js is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. web3.js is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ import { HexString } from 'web3-types'; import { bytesToHex } from 'web3-utils'; import { setLengthLeft, toUint8Array } from '../common/utils.js'; import type { AccessList, AccessListUint8Array, AccessListItem } from './types.js'; import { isAccessList } from './types.js'; import type { Common } from '../common/common.js'; export const checkMaxInitCodeSize = (common: Common, length: number) => { const maxInitCodeSize = common.param('vm', 'maxInitCodeSize'); if (maxInitCodeSize && BigInt(length) > maxInitCodeSize) { throw new Error( `the initcode size of this transaction is too large: it is ${length} while the max is ${common.param( 'vm', 'maxInitCodeSize', )}`, ); } }; export const getAccessListData = (accessList: AccessListUint8Array | AccessList) => { let AccessListJSON; let uint8arrayAccessList; if (isAccessList(accessList)) { AccessListJSON = accessList; const newAccessList: AccessListUint8Array = []; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < accessList.length; i += 1) { const item: AccessListItem = accessList[i]; const addressBytes = toUint8Array(item.address); const storageItems: Uint8Array[] = []; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let index = 0; index < item.storageKeys.length; index += 1) { storageItems.push(toUint8Array(item.storageKeys[index])); } newAccessList.push([addressBytes, storageItems]); } uint8arrayAccessList = newAccessList; } else { uint8arrayAccessList = accessList ?? []; // build the JSON const json: AccessList = []; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < uint8arrayAccessList.length; i += 1) { const data = uint8arrayAccessList[i]; const address = bytesToHex(data[0]); const storageKeys: string[] = []; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let item = 0; item < data[1].length; item += 1) { storageKeys.push(bytesToHex(data[1][item])); } const jsonItem: AccessListItem = { address, storageKeys, }; json.push(jsonItem); } AccessListJSON = json; } return { AccessListJSON, accessList: uint8arrayAccessList, }; }; export const verifyAccessList = (accessList: AccessListUint8Array) => { // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let key = 0; key < accessList.length; key += 1) { const accessListItem = accessList[key]; const address = accessListItem[0]; const storageSlots = accessListItem[1]; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/consistent-type-assertions if ((accessListItem)[2] !== undefined) { throw new Error( 'Access list item cannot have 3 elements. It can only have an address, and an array of storage slots.', ); } if (address.length !== 20) { throw new Error('Invalid EIP-2930 transaction: address length should be 20 bytes'); } // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let storageSlot = 0; storageSlot < storageSlots.length; storageSlot += 1) { if (storageSlots[storageSlot].length !== 32) { throw new Error( 'Invalid EIP-2930 transaction: storage slot length should be 32 bytes', ); } } } }; export const getAccessListJSON = ( accessList: AccessListUint8Array, ): { address: HexString; storageKeys: HexString[]; }[] => { const accessListJSON: { address: HexString; storageKeys: HexString[] }[] = []; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let index = 0; index < accessList.length; index += 1) { const item: any = accessList[index]; const JSONItem: { address: HexString; storageKeys: HexString[] } = { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/consistent-type-assertions address: bytesToHex(setLengthLeft(item[0], 20)), storageKeys: [], }; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/prefer-optional-chain const storageSlots: Uint8Array[] = item && item[1]; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let slot = 0; slot < storageSlots.length; slot += 1) { const storageSlot = storageSlots[slot]; JSONItem.storageKeys.push(bytesToHex(setLengthLeft(storageSlot, 32))); } accessListJSON.push(JSONItem); } return accessListJSON; }; export const getDataFeeEIP2930 = (accessList: AccessListUint8Array, common: Common): number => { const accessListStorageKeyCost = common.param('gasPrices', 'accessListStorageKeyCost'); const accessListAddressCost = common.param('gasPrices', 'accessListAddressCost'); let slots = 0; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let index = 0; index < accessList.length; index += 1) { const item = accessList[index]; const storageSlots = item[1]; slots += storageSlots.length; } const addresses = accessList.length; return addresses * Number(accessListAddressCost) + slots * Number(accessListStorageKeyCost); };