Skip to content

Commit 19c2af6

Browse files
authored
Detruffle check-versions script (#11490)
1 parent 3aba928 commit 19c2af6

File tree

148 files changed

+2777
-182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

148 files changed

+2777
-182
lines changed

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ packages/protocol/types/
1919
packages/protocol/scripts/**/*.js
2020
packages/protocol/migrations/**/*.js
2121
packages/protocol/test/**/*.js
22+
packages/protocol/test-ts/**/*.js
2223
packages/protocol/contractPackages.js
2324
packages/protocol/abis/src-generated/
2425

packages/env-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"devDependencies": {
3333
"@tsconfig/recommended": "^1.0.3",
3434
"@jest/globals": "^29.5.0",
35+
"@types/bunyan": "^1.8.11",
3536
"typescript": "^5.3.3"
3637
}
3738
}

packages/env-tests/src/context.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Address, ContractKit } from '@celo/contractkit'
2-
// @ts-expect-error module started failing
32
import Logger from 'bunyan'
43
export interface EnvTestContext {
54
kit: ContractKit

packages/env-tests/src/logger.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// @ts-expect-error module started failing
21
import Logger, { createLogger, levelFromName, LogLevelString, stdSerializers } from 'bunyan'
32
import bunyanDebugStream from 'bunyan-debug-stream'
43
import { createStream } from 'bunyan-gke-stackdriver'

packages/protocol/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ scripts/**/*.js.map
1818
test/**/*.js
1919
test/**/*.js.map
2020

21+
test-ts/**/*.js
22+
2123
types/**/*.js
2224
types/**/*.js.map
2325

packages/protocol/CHEATSHEET.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ Covers changes in `package.json` scripts introduced starting with PR [#11369](ht
2828
| `...` | `test` |
2929
| `test:coverage` | `test:coverage` |
3030
| `gas` | `test:gas` |
31-
| `quicktest` | `test:quicktest` |
3231
| `test:release-snapshots` | `test:release-snapshots` |
3332
| `test:scripts` | `test:scripts` |
3433
| `test` | `test:truffle` |

packages/protocol/README.md

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,25 +85,6 @@ yarn run test:truffle ${contract name}
8585

8686
Adding the optional `--gas` flag will print out a report of contract gas usage.
8787

88-
For quick test iterations run:
89-
90-
```bash
91-
yarn run test:quicktest
92-
```
93-
94-
or for a single contract:
95-
96-
```bash
97-
yarn run test:quicktest ${contract name}
98-
```
99-
100-
For `test:quicktest` to work correctly a contract's migration dependencies have to be uncommented in `scripts/bash/backupmigrations.sh`.
101-
102-
Compared to the normal test command, quicktest will:
103-
104-
1. Not run the pretest script of building solidity (will still be run as part of truffle test) and compiling typescript. This works because truffle can run typescript "natively".
105-
2. Only migrate selected migrations as set in `backupmigrations.sh` (you'll likely need at least one compilation step since truffle seems to only run compiled migrations)
106-
10788
## Making a new release (Foundry)
10889

10990
To create a new release using the Foundry script, run the following command:

packages/protocol/lib/compatibility/ast-code.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
MethodMutabilityChange, MethodRemovedChange, MethodReturnChange,
66
MethodVisibilityChange, NewContractChange
77
} from '@celo/protocol/lib/compatibility/change'
8-
import { makeZContract } from '@celo/protocol/lib/compatibility/internal'
8+
import { makeZContract, getContractName, getArtifactByName } from '@celo/protocol/lib/compatibility/internal'
99
import {
1010
BuildArtifacts,
1111
Contract as ZContract
@@ -259,10 +259,19 @@ export function reportASTIncompatibilities(
259259
let out: ASTCodeCompatibilityReport[] = []
260260
for (const newArtifacts of newArtifactsSets) {
261261
const reports = newArtifacts.listArtifacts()
262+
.filter((newArtifact) => {
263+
// Matches all Truffle project artifacts (core contracts and test resource contracts)
264+
const truffleProjectContractPathPattern = /^project:/
265+
// Matches Foundry core contracts
266+
const foundryCoreContractPathPattern = /^contracts(-0\.8)?\//
267+
// Matches Foundry test resource contracts
268+
const foundryTestContractPathPattern = /^test-ts/
269+
const path = newArtifact.ast.absolutePath
270+
return truffleProjectContractPathPattern.test(path) || foundryCoreContractPathPattern.test(path) || foundryTestContractPathPattern.test(path)
271+
})
262272
.map((newArtifact) => {
263-
264273
for (const oldArtifacts of oldArtifactsSet) {
265-
const oldArtifact = oldArtifacts.getArtifactByName(newArtifact.contractName)
274+
const oldArtifact = getArtifactByName(getContractName(newArtifact), oldArtifacts)
266275
if (oldArtifact) {
267276
return generateASTCompatibilityReport(makeZContract(oldArtifact), oldArtifacts, makeZContract(newArtifact), newArtifacts)
268277
}
@@ -271,7 +280,6 @@ export function reportASTIncompatibilities(
271280
return generateASTCompatibilityReport(null, oldArtifactsSet[0], makeZContract(newArtifact), newArtifacts)
272281
})
273282
out = [...out, ...reports]
274-
275283
}
276284

277285
return mergeReports(out)

packages/protocol/lib/compatibility/ast-layout.ts

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,11 @@
1-
import { Contract as Web3Contract } from '@celo/connect';
2-
import { Artifact, TypeInfo } from '@celo/protocol/lib/compatibility/internal';
1+
import { Artifact, TypeInfo, makeZContract, getContractName, getArtifactByName } from '@celo/protocol/lib/compatibility/internal';
32
import {
43
BuildArtifacts,
54
Operation,
65
StorageLayoutInfo,
7-
Contract as ZContract,
86
compareStorageLayouts,
97
getStorageLayout
108
} from '@openzeppelin/upgrades';
11-
const Web3 = require('web3')
12-
13-
const web3 = new Web3(null)
14-
15-
// getStorageLayout needs an oz-sdk Contract class instance. This class is a
16-
// subclass of Contract from web3-eth-contract, with an added .schema member and
17-
// several methods.
18-
//
19-
// Couldn't find an easy way of getting one just from contract artifacts. But
20-
// for getStorageLayout we really only need .schema.ast and .schema.contractName.
21-
const addSchemaForLayoutChecking = (web3Contract: Web3Contract, artifact: any): ZContract => {
22-
// @ts-ignore
23-
const contract = web3Contract as Contract
24-
// @ts-ignore
25-
contract.schema = {}
26-
contract.schema.ast = artifact.ast
27-
contract.schema.contractName = artifact.contractName
28-
return contract
29-
}
30-
31-
const makeZContract = (artifact: any): ZContract => {
32-
const contract = new web3.eth.Contract(artifact.abi)
33-
34-
return addSchemaForLayoutChecking(contract, artifact)
35-
}
369

3710
export const getLayout = (artifact: Artifact, artifacts: BuildArtifacts) => {
3811
const contract = makeZContract(artifact)
@@ -200,15 +173,15 @@ export const generateCompatibilityReport = (oldArtifact: Artifact, oldArtifacts:
200173
const structsReport = generateStructsCompatibilityReport(oldLayout, newLayout)
201174

202175
if (!layoutReport.compatible) {
203-
console.log(newArtifact.contractName, "layoutReport incompatible", JSON.stringify(layoutReport.errors));
176+
console.log(getContractName(newArtifact), "layoutReport incompatible", JSON.stringify(layoutReport.errors));
204177
}
205178

206179
if (!structsReport.compatible) {
207-
console.log(newArtifact.contractName, "structsReport incompatible", JSON.stringify(structsReport.errors));
180+
console.log(getContractName(newArtifact), "structsReport incompatible", JSON.stringify(structsReport.errors));
208181
}
209182

210183
return {
211-
contract: newArtifact.contractName,
184+
contract: getContractName(newArtifact),
212185
compatible: layoutReport.compatible && structsReport.compatible,
213186
errors: layoutReport.errors.concat(structsReport.errors),
214187
expanded: structsReport.expanded
@@ -218,10 +191,20 @@ export const generateCompatibilityReport = (oldArtifact: Artifact, oldArtifacts:
218191
export const reportLayoutIncompatibilities = (oldArtifactsSet: BuildArtifacts[], newArtifactsSets: BuildArtifacts[]): ASTStorageCompatibilityReport[] => {
219192
let out: ASTStorageCompatibilityReport[] = []
220193
for (const newArtifacts of newArtifactsSets) {
221-
const reports = newArtifacts.listArtifacts().map((newArtifact) => {
222-
194+
const reports = newArtifacts.listArtifacts()
195+
.filter((newArtifact: any) => {
196+
// Matches all Truffle project artifacts (core contracts and test resource contracts)
197+
const truffleProjectContractPathPattern = /^project:/
198+
// Matches Foundry core contracts
199+
const foundryCoreContractPathPattern = /^contracts(-0\.8)?\//
200+
// Matches Foundry test resource contracts
201+
const foundryTestContractPathPattern = /^test-ts/
202+
const path = newArtifact.ast.absolutePath
203+
return truffleProjectContractPathPattern.test(path) || foundryCoreContractPathPattern.test(path) || foundryTestContractPathPattern.test(path)
204+
})
205+
.map((newArtifact: any) => {
223206
for (const oldArtifacts of oldArtifactsSet) {
224-
const oldArtifact = oldArtifacts.getArtifactByName(newArtifact.contractName)
207+
const oldArtifact: any = getArtifactByName(getContractName(newArtifact), oldArtifacts)
225208
if (oldArtifact !== undefined) {
226209
return generateCompatibilityReport(oldArtifact, oldArtifacts, newArtifact, newArtifacts)
227210
}
@@ -230,7 +213,7 @@ export const reportLayoutIncompatibilities = (oldArtifactsSet: BuildArtifacts[],
230213
// Generate an empty report for new contracts, which are, by definition, backwards
231214
// compatible.
232215
return {
233-
contract: newArtifact.contractName,
216+
contract: getContractName(newArtifact),
234217
compatible: true,
235218
errors: []
236219
}

packages/protocol/lib/compatibility/ast-version.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable max-classes-per-file: 0 */
2-
import { Artifact } from '@celo/protocol/lib/compatibility/internal';
2+
import { Artifact, getContractName } from '@celo/protocol/lib/compatibility/internal';
33
import { ContractVersion, ContractVersionChecker, ContractVersionCheckerIndex, ContractVersionDelta, ContractVersionDeltaIndex, ContractVersionIndex, DEFAULT_VERSION_STRING } from '@celo/protocol/lib/compatibility/version';
44
import { Address as EJSAddress } from "@ethereumjs/util";
55
import { VM } from "@ethereumjs/vm";
@@ -11,12 +11,12 @@ const abi = require('ethereumjs-abi')
1111
* A mapping {contract name => {@link ContractVersion}}.
1212
*/
1313
export class ASTContractVersions {
14-
static fromArtifacts = async (artifactsSet: BuildArtifacts[]): Promise<ASTContractVersions> => {
14+
static fromArtifacts = async (artifactsSet: BuildArtifacts[], newLinking: boolean): Promise<ASTContractVersions> => {
1515
const contracts = {}
1616

1717
for (const artifacts of artifactsSet) {
18-
await Promise.all(artifacts.listArtifacts().filter(c => !isLibrary(c.contractName, [artifacts])).map(async (artifact) => {
19-
contracts[artifact.contractName] = await getContractVersion(artifact)
18+
await Promise.all(artifacts.listArtifacts().filter(c => !isLibrary(getContractName(c), [artifacts])).map(async (artifact) => {
19+
contracts[getContractName(artifact)] = await getContractVersion(artifact, newLinking)
2020
}))
2121
}
2222

@@ -30,15 +30,19 @@ export class ASTContractVersions {
3030
* Gets the version of a contract by calling Contract.getVersionNumber() on
3131
* the contract deployed bytecode.
3232
*
33+
* If `newLinking` is true, expects `__$<hash>$__` style linking. Otherwise, `__<LibraryName>____`
34+
* style.
35+
*
3336
* If the contract version cannot be retrieved, returns version 1.1.0.0 by default.
3437
*/
35-
export async function getContractVersion(artifact: Artifact): Promise<ContractVersion> {
38+
export async function getContractVersion(artifact: Artifact, newLinking: boolean): Promise<ContractVersion> {
3639
const vm = await VM.create();
37-
const bytecode = artifact.deployedBytecode
40+
// @ts-ignore
41+
const bytecode = artifact.deployedBytecode.object || artifact.deployedBytecode
3842
const data = '0x' + abi.methodID('getVersionNumber', []).toString('hex')
3943
const nullAddress = '0000000000000000000000000000000000000000'
40-
// Artificially link all libraries to the null address.
41-
const linkedBytecode = bytecode.split(/[_]+[A-Za-z0-9]+[_]+/).join(nullAddress)
44+
const compilerLinkRegex = newLinking ? /__\$[a-f0-9]{34}\$__/g : /__[A-Za-z0-9_]{36}__/g
45+
const linkedBytecode = bytecode.split(compilerLinkRegex).join(nullAddress)
4246
const result = await vm.evm.runCall({
4347
to: new EJSAddress(Buffer.from(nullAddress, 'hex')),
4448
caller: new EJSAddress(Buffer.from(nullAddress, 'hex')),
@@ -57,9 +61,9 @@ export async function getContractVersion(artifact: Artifact): Promise<ContractVe
5761
}
5862

5963
export class ASTContractVersionsChecker {
60-
static create = async (oldArtifactsSet: BuildArtifacts[], newArtifactsSet: BuildArtifacts[], expectedVersionDeltas: ContractVersionDeltaIndex): Promise<ASTContractVersionsChecker> => {
61-
const oldVersions = await ASTContractVersions.fromArtifacts(oldArtifactsSet)
62-
const newVersions = await ASTContractVersions.fromArtifacts(newArtifactsSet)
64+
static create = async (oldArtifactsSet: BuildArtifacts[], newArtifactsSet: BuildArtifacts[], expectedVersionDeltas: ContractVersionDeltaIndex, newLinking: boolean): Promise<ASTContractVersionsChecker> => {
65+
const oldVersions = await ASTContractVersions.fromArtifacts(oldArtifactsSet, newLinking)
66+
const newVersions = await ASTContractVersions.fromArtifacts(newArtifactsSet, newLinking)
6367
const contracts = {}
6468
Object.keys(newVersions.contracts).map((contract: string) => {
6569
const versionDelta = expectedVersionDeltas[contract] === undefined ? ContractVersionDelta.fromChanges(false, false, false, false) : expectedVersionDeltas[contract]

0 commit comments

Comments
 (0)