-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add missing system contracts to the DB
- Loading branch information
1 parent
63c757c
commit 865efe2
Showing
7 changed files
with
260 additions
and
172 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
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
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
107 changes: 107 additions & 0 deletions
107
packages/worker/src/contracts/systemContract.service.spec.ts
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,107 @@ | ||
import { mock } from "jest-mock-extended"; | ||
import { Test, TestingModule } from "@nestjs/testing"; | ||
import { Logger } from "@nestjs/common"; | ||
import { BlockchainService } from "../blockchain/blockchain.service"; | ||
import { AddressRepository } from "../repositories/address.repository"; | ||
import { SystemContractService } from "./systemContract.service"; | ||
import { Address } from "../entities"; | ||
|
||
describe("SystemContractService", () => { | ||
let systemContractService: SystemContractService; | ||
let blockchainServiceMock: BlockchainService; | ||
let addressRepositoryMock: AddressRepository; | ||
const systemContracts = SystemContractService.getSystemContracts(); | ||
|
||
beforeEach(async () => { | ||
blockchainServiceMock = mock<BlockchainService>({ | ||
getCode: jest.fn().mockImplementation((address: string) => Promise.resolve(`${address}-code`)), | ||
}); | ||
|
||
addressRepositoryMock = mock<AddressRepository>({ | ||
find: jest.fn(), | ||
}); | ||
|
||
const app: TestingModule = await Test.createTestingModule({ | ||
providers: [ | ||
SystemContractService, | ||
{ | ||
provide: BlockchainService, | ||
useValue: blockchainServiceMock, | ||
}, | ||
{ | ||
provide: AddressRepository, | ||
useValue: addressRepositoryMock, | ||
}, | ||
], | ||
}).compile(); | ||
|
||
app.useLogger(mock<Logger>()); | ||
systemContractService = app.get<SystemContractService>(SystemContractService); | ||
}); | ||
|
||
describe("addSystemContracts", () => { | ||
it("doesn't add any system contracts if they already exist in DB", async () => { | ||
(addressRepositoryMock.find as jest.Mock).mockResolvedValue( | ||
SystemContractService.getSystemContracts().map((contract) => mock<Address>({ address: contract.address })) | ||
); | ||
await systemContractService.addSystemContracts(); | ||
expect(addressRepositoryMock.add).toBeCalledTimes(0); | ||
}); | ||
|
||
it("adds all system contracts if none of them exist in the DB", async () => { | ||
(addressRepositoryMock.find as jest.Mock).mockResolvedValue([]); | ||
await systemContractService.addSystemContracts(); | ||
expect(addressRepositoryMock.add).toBeCalledTimes(systemContracts.length); | ||
for (const systemContract of systemContracts) { | ||
expect(addressRepositoryMock.add).toBeCalledWith({ | ||
address: systemContract.address, | ||
bytecode: `${systemContract.address}-code`, | ||
}); | ||
} | ||
}); | ||
|
||
it("adds only missing system contracts", async () => { | ||
const existingContractAddresses = [ | ||
"0x000000000000000000000000000000000000800d", | ||
"0x0000000000000000000000000000000000008006", | ||
]; | ||
(addressRepositoryMock.find as jest.Mock).mockResolvedValue( | ||
existingContractAddresses.map((existingContractAddress) => mock<Address>({ address: existingContractAddress })) | ||
); | ||
await systemContractService.addSystemContracts(); | ||
expect(addressRepositoryMock.add).toBeCalledTimes(systemContracts.length - existingContractAddresses.length); | ||
for (const systemContract of systemContracts) { | ||
if (!existingContractAddresses.includes(systemContract.address)) { | ||
expect(addressRepositoryMock.add).toBeCalledWith({ | ||
address: systemContract.address, | ||
bytecode: `${systemContract.address}-code`, | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
it("adds contracts only if they are deployed to the network", async () => { | ||
const notDeployedSystemContracts = [ | ||
"0x000000000000000000000000000000000000800d", | ||
"0x0000000000000000000000000000000000008006", | ||
]; | ||
(addressRepositoryMock.find as jest.Mock).mockResolvedValue([]); | ||
(blockchainServiceMock.getCode as jest.Mock).mockImplementation(async (address: string) => { | ||
if (notDeployedSystemContracts.includes(address)) { | ||
return "0x"; | ||
} | ||
return `${address}-code`; | ||
}); | ||
await systemContractService.addSystemContracts(); | ||
expect(addressRepositoryMock.add).toBeCalledTimes(systemContracts.length - notDeployedSystemContracts.length); | ||
for (const systemContract of systemContracts) { | ||
if (!notDeployedSystemContracts.includes(systemContract.address)) { | ||
expect(addressRepositoryMock.add).toBeCalledWith({ | ||
address: systemContract.address, | ||
bytecode: `${systemContract.address}-code`, | ||
}); | ||
} | ||
} | ||
}); | ||
}); | ||
}); |
143 changes: 143 additions & 0 deletions
143
packages/worker/src/contracts/systemContract.service.ts
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,143 @@ | ||
import { Injectable } from "@nestjs/common"; | ||
import { BlockchainService } from "../blockchain/blockchain.service"; | ||
import { AddressRepository } from "../repositories"; | ||
import { In } from "typeorm"; | ||
|
||
@Injectable() | ||
export class SystemContractService { | ||
constructor( | ||
private readonly addressRepository: AddressRepository, | ||
private readonly blockchainService: BlockchainService | ||
) {} | ||
|
||
public async addSystemContracts(): Promise<void> { | ||
const systemContracts = SystemContractService.getSystemContracts(); | ||
const existingContracts = await this.addressRepository.find({ | ||
where: { | ||
address: In(systemContracts.map((contract) => contract.address)), | ||
}, | ||
select: { | ||
address: true, | ||
}, | ||
}); | ||
|
||
for (const contract of systemContracts) { | ||
if (!existingContracts.find((existingContract) => existingContract.address === contract.address)) { | ||
const bytecode = await this.blockchainService.getCode(contract.address); | ||
// some contract might not exist on the environment yet | ||
if (bytecode !== "0x") { | ||
await this.addressRepository.add({ | ||
address: contract.address, | ||
bytecode, | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public static getSystemContracts() { | ||
// name attribute is never used, it's just for better readability & understanding | ||
return [ | ||
{ | ||
address: "0x0000000000000000000000000000000000000000", | ||
name: "EmptyContract", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000000001", | ||
name: "Ecrecover", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000000002", | ||
name: "SHA256", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000000006", | ||
name: "EcAdd", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000000007", | ||
name: "EcMul", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000000008", | ||
name: "EcPairing", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008001", | ||
name: "EmptyContract", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008002", | ||
name: "AccountCodeStorage", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008003", | ||
name: "NonceHolder", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008004", | ||
name: "KnownCodesStorage", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008005", | ||
name: "ImmutableSimulator", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008006", | ||
name: "ContractDeployer", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008008", | ||
name: "L1Messenger", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008009", | ||
name: "MsgValueSimulator", | ||
}, | ||
{ | ||
address: "0x000000000000000000000000000000000000800a", | ||
name: "L2BaseToken", | ||
}, | ||
{ | ||
address: "0x000000000000000000000000000000000000800b", | ||
name: "SystemContext", | ||
}, | ||
{ | ||
address: "0x000000000000000000000000000000000000800c", | ||
name: "BootloaderUtilities", | ||
}, | ||
{ | ||
address: "0x000000000000000000000000000000000000800d", | ||
name: "EventWriter", | ||
}, | ||
{ | ||
address: "0x000000000000000000000000000000000000800e", | ||
name: "Compressor", | ||
}, | ||
{ | ||
address: "0x000000000000000000000000000000000000800f", | ||
name: "ComplexUpgrader", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008010", | ||
name: "Keccak256", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008012", | ||
name: "CodeOracle", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000000100", | ||
name: "P256Verify", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000008011", | ||
name: "PubdataChunkPublisher", | ||
}, | ||
{ | ||
address: "0x0000000000000000000000000000000000010000", | ||
name: "Create2Factory", | ||
}, | ||
]; | ||
} | ||
} |
Oops, something went wrong.