Skip to content

Commit 52aef0e

Browse files
Verification flow refactoring (#1845)
This is the main pull request for the verification flow refactoring. Smaller feature-specific pull requests were merged into this branch before it was finalized. See #1665 for more details
2 parents e26ac1f + 2b08df2 commit 52aef0e

File tree

265 files changed

+28346
-7241
lines changed

Some content is hidden

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

265 files changed

+28346
-7241
lines changed

packages/lib-sourcify/README.md

+341-121
Large diffs are not rendered by default.

packages/lib-sourcify/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"check": "run-s check:*",
1919
"check:eslint": "eslint . --ext .ts",
2020
"check:prettier": "prettier \"./**/*.ts\" --check",
21-
"test": "c8 --reporter=none mocha -r ts-node/register test/**/*.spec.ts --no-timeout --exit",
21+
"test": "c8 --reporter=none mocha -r ts-node/register test/**/*.spec.ts test/*.spec.ts --no-timeout --exit",
2222
"check-cli": "run-s test diff-integration-tests check-integration-tests",
2323
"check-integration-tests": "run-s check-integration-test:*",
2424
"diff-integration-tests": "mkdir -p diff && rm -rf diff/test && cp -r test diff/test && rm -rf diff/test/test-*/.git && cd diff && git init --quiet && git add -A && git commit --quiet --no-verify --allow-empty -m 'WIP' && echo '\\n\\nCommitted most recent integration test output in the \"diff\" directory. Review the changes with \"cd diff && git diff HEAD\" or your preferred git diff viewer.'",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { AuxdataStyle } from '@ethereum-sourcify/bytecode-utils';
2+
import {
3+
CompilationTarget,
4+
CompiledContractCborAuxdata,
5+
Metadata,
6+
CompilationLanguage,
7+
StringMap,
8+
LinkReferences,
9+
CompilationError,
10+
} from './CompilationTypes';
11+
import {
12+
ImmutableReferences,
13+
ISolidityCompiler,
14+
SolidityJsonInput,
15+
SolidityOutput,
16+
SolidityOutputContract,
17+
} from './SolidityTypes';
18+
import {
19+
IVyperCompiler,
20+
VyperJsonInput,
21+
VyperOutput,
22+
VyperOutputContract,
23+
} from './VyperTypes';
24+
import { logInfo, logSilly, logWarn } from '../logger';
25+
26+
export abstract class AbstractCompilation {
27+
/**
28+
* Constructor parameters
29+
*/
30+
abstract compiler: ISolidityCompiler | IVyperCompiler;
31+
abstract compilerVersion: string;
32+
abstract compilationTarget: CompilationTarget;
33+
abstract jsonInput: SolidityJsonInput | VyperJsonInput;
34+
35+
protected _metadata?: Metadata;
36+
compilerOutput?: SolidityOutput | VyperOutput;
37+
38+
abstract auxdataStyle: AuxdataStyle;
39+
abstract language: CompilationLanguage;
40+
41+
/** Marks the positions of the CborAuxdata parts in the bytecode */
42+
protected _creationBytecodeCborAuxdata?: CompiledContractCborAuxdata;
43+
protected _runtimeBytecodeCborAuxdata?: CompiledContractCborAuxdata;
44+
45+
/**
46+
* Recompiles the contract with the specified compiler settings
47+
* @param forceEmscripten Whether to force using the WebAssembly binary for compilation (only for Solidity)
48+
*/
49+
abstract compile(forceEmscripten?: boolean): Promise<void>;
50+
abstract generateCborAuxdataPositions(
51+
forceEmscripten?: boolean,
52+
): Promise<void>;
53+
54+
public async compileAndReturnCompilationTarget(
55+
forceEmscripten = false,
56+
): Promise<SolidityOutputContract | VyperOutputContract> {
57+
const version = this.compilerVersion;
58+
59+
const compilationStartTime = Date.now();
60+
logInfo('Compiling contract', {
61+
version,
62+
contract: this.compilationTarget.name,
63+
path: this.compilationTarget.path,
64+
forceEmscripten,
65+
});
66+
logSilly('Compilation input', { solcJsonInput: this.jsonInput });
67+
this.compilerOutput = await this.compiler.compile(
68+
version,
69+
this.jsonInput as any,
70+
forceEmscripten,
71+
);
72+
if (this.compilerOutput === undefined) {
73+
logWarn('Compiler error', {
74+
errorMessages: ['compilerOutput is undefined'],
75+
});
76+
throw new CompilationError('Compiler error', 'compiler_error');
77+
}
78+
79+
// We call contractCompilerOutput() before logging because it can throw an error
80+
const compilationTargetContract = this.contractCompilerOutput;
81+
82+
const compilationEndTime = Date.now();
83+
const compilationDuration = compilationEndTime - compilationStartTime;
84+
logSilly('Compilation output', { compilerOutput: this.compilerOutput });
85+
logInfo('Compiled contract', {
86+
version,
87+
contract: this.compilationTarget.name,
88+
path: this.compilationTarget.path,
89+
forceEmscripten,
90+
compilationDuration: `${compilationDuration}ms`,
91+
});
92+
93+
return compilationTargetContract;
94+
}
95+
96+
get contractCompilerOutput(): SolidityOutputContract | VyperOutputContract {
97+
if (!this.compilerOutput) {
98+
logWarn('Compiler output is undefined');
99+
throw new Error('Compiler output is undefined');
100+
}
101+
if (
102+
!this.compilerOutput.contracts ||
103+
!this.compilerOutput.contracts[this.compilationTarget.path] ||
104+
!this.compilerOutput.contracts[this.compilationTarget.path][
105+
this.compilationTarget.name
106+
]
107+
) {
108+
const error = new Error('Contract not found in compiler output');
109+
logWarn('Contract not found in compiler output');
110+
throw error;
111+
}
112+
return this.compilerOutput.contracts[this.compilationTarget.path][
113+
this.compilationTarget.name
114+
];
115+
}
116+
117+
get creationBytecode() {
118+
return `0x${this.contractCompilerOutput.evm.bytecode.object}`;
119+
}
120+
121+
get runtimeBytecode() {
122+
return `0x${this.contractCompilerOutput.evm.deployedBytecode.object}`;
123+
}
124+
125+
get metadata() {
126+
if (!this._metadata) {
127+
throw new Error('Metadata is not set');
128+
}
129+
return this._metadata;
130+
}
131+
132+
get sources() {
133+
return Object.keys(this.jsonInput.sources).reduce((acc, source) => {
134+
acc[source] = this.jsonInput.sources[source].content;
135+
return acc;
136+
}, {} as StringMap);
137+
}
138+
139+
abstract get immutableReferences(): ImmutableReferences;
140+
abstract get runtimeLinkReferences(): LinkReferences;
141+
abstract get creationLinkReferences(): LinkReferences;
142+
143+
get creationBytecodeCborAuxdata(): CompiledContractCborAuxdata {
144+
if (!this._creationBytecodeCborAuxdata) {
145+
throw new Error('Creation bytecode cbor auxdata is not set');
146+
}
147+
return this._creationBytecodeCborAuxdata;
148+
}
149+
150+
get runtimeBytecodeCborAuxdata(): CompiledContractCborAuxdata {
151+
if (!this._runtimeBytecodeCborAuxdata) {
152+
throw new Error('Runtime bytecode cbor auxdata is not set');
153+
}
154+
return this._runtimeBytecodeCborAuxdata;
155+
}
156+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { Abi } from 'abitype';
2+
import { SoliditySettings } from './SolidityTypes';
3+
import { SourcifyLibError } from '../SourcifyLibError';
4+
5+
export interface LinkReferences {
6+
[filePath: string]: {
7+
[libraryName: string]: [
8+
{
9+
length: number;
10+
start: number;
11+
},
12+
];
13+
};
14+
}
15+
16+
export interface MetadataSource {
17+
keccak256: string;
18+
content?: string;
19+
urls?: string[];
20+
license?: string;
21+
}
22+
23+
export interface MetadataSourceMap {
24+
[index: string]: MetadataSource;
25+
}
26+
27+
export interface Devdoc {
28+
author?: string;
29+
details?: string;
30+
errors?: {
31+
[index: string]: {
32+
details?: string;
33+
};
34+
};
35+
events?: {
36+
[index: string]: {
37+
details?: string;
38+
params?: any;
39+
};
40+
};
41+
kind: 'dev';
42+
methods: {
43+
[index: string]: {
44+
details?: string;
45+
params?: any;
46+
returns?: any;
47+
};
48+
};
49+
stateVariables?: any;
50+
title?: string;
51+
version?: number;
52+
}
53+
54+
export interface Userdoc {
55+
errors?: {
56+
[index: string]: {
57+
notice?: string;
58+
}[];
59+
};
60+
events?: {
61+
[index: string]: {
62+
notice?: string;
63+
};
64+
};
65+
kind: 'user';
66+
methods: {
67+
[index: string]: {
68+
notice: string;
69+
};
70+
};
71+
version?: number;
72+
}
73+
74+
export interface MetadataOutput {
75+
abi: Abi;
76+
devdoc?: Devdoc;
77+
userdoc?: Userdoc;
78+
}
79+
80+
// Metadata JSON's "settings" does have extra "compilationTarget" and its "libraries" field is in a different format
81+
// ( libraries["MyContract.sol:Mycontract"]:"0xab..cd" vs libraries["MyContract.sol"]["MyContract"]:"0xab..cd")
82+
export interface MetadataCompilerSettings
83+
extends Omit<SoliditySettings, 'libraries' | 'outputSelection'> {
84+
compilationTarget: {
85+
[sourceName: string]: string;
86+
};
87+
libraries?: {
88+
[index: string]: string;
89+
};
90+
}
91+
92+
// Metadata type that reflects the metadata object from
93+
// https://docs.soliditylang.org/en/latest/metadata.html
94+
export interface Metadata {
95+
compiler: {
96+
keccak256?: string;
97+
version: string;
98+
};
99+
language: string;
100+
output: MetadataOutput;
101+
settings: MetadataCompilerSettings;
102+
sources: MetadataSourceMap;
103+
version: number;
104+
}
105+
106+
export interface CompiledContractCborAuxdata {
107+
[index: string]: {
108+
offset: number;
109+
value: string;
110+
};
111+
}
112+
113+
export interface StringMap {
114+
[key: string]: string;
115+
}
116+
117+
export interface AuxdataDiff {
118+
real: string;
119+
diffStart: number;
120+
diff: string;
121+
}
122+
123+
export interface CompilationTarget {
124+
name: string;
125+
path: string;
126+
}
127+
128+
export type CompilationLanguage = 'Solidity' | 'Vyper';
129+
130+
export type CompilationErrorCode =
131+
| 'cannot_generate_cbor_auxdata_positions'
132+
| 'invalid_compiler_version'
133+
| 'contract_not_found_in_compiler_output'
134+
| 'compiler_error';
135+
136+
export class CompilationError extends SourcifyLibError {
137+
constructor(message: string, code: CompilationErrorCode) {
138+
super(message, code);
139+
}
140+
}

0 commit comments

Comments
 (0)