Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verification flow verification classes #1879

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0443681
implement Verifcation.ts
marcocastignoli Jan 30, 2025
5455f98
Refactor Verification.ts
marcocastignoli Jan 30, 2025
bacfe4a
Add tests
marcocastignoli Jan 30, 2025
da81e76
Add more tests
marcocastignoli Jan 30, 2025
268ceae
Add comment to tests
marcocastignoli Jan 30, 2025
8e0a65a
Add Vyper tests in Verification
marcocastignoli Jan 30, 2025
d620bee
refactor Verification class
marcocastignoli Feb 3, 2025
06e32f7
handle ContructorTransformation
marcocastignoli Feb 3, 2025
77d3f06
add comment
marcocastignoli Feb 3, 2025
0f44239
Refactor runtime bytecode matching and add call protection transforma…
marcocastignoli Feb 3, 2025
1a2bbc7
Refactor Verification class to use getter methods and improve encapsu…
marcocastignoli Feb 3, 2025
95ffdf4
Refactor AbstractCompilation to use protected properties and getter m…
marcocastignoli Feb 3, 2025
f32de54
Move check transformation functions into Verification class
marcocastignoli Feb 4, 2025
aa62bdc
restore old `verification.ts` tests
marcocastignoli Feb 4, 2025
1f267f6
fix constructor arguments trasformantion tests
marcocastignoli Feb 4, 2025
ef83999
restore old `types.ts`
marcocastignoli Feb 4, 2025
4bd7b6b
add VerificationError class
marcocastignoli Feb 4, 2025
38c726b
Implement Vyper constructor argument transformation test
marcocastignoli Feb 4, 2025
4bb267e
Pass forceEmscripten option to compilation call
manuelwedler Feb 4, 2025
5cbd7d5
Split library map into runtime and creation maps
marcocastignoli Feb 4, 2025
b1a8195
replace expectMatch with expectVerification
marcocastignoli Feb 4, 2025
181bc29
fix "should verify a contract with viaIR:true, optimizer disabled, an…
marcocastignoli Feb 4, 2025
fecc3ba
Add test for library verification with call protection transformation
marcocastignoli Feb 4, 2025
c31aaa8
fix call protection test
marcocastignoli Feb 4, 2025
591cb3a
increase coverage
marcocastignoli Feb 4, 2025
ff15507
add missing tests from verification.spec.ts increasing coverage
marcocastignoli Feb 4, 2025
abde5fa
Refactor bytecode transformations and verification logic
marcocastignoli Feb 6, 2025
577fb48
fix linting
marcocastignoli Feb 6, 2025
3d68742
Refactor error handling and type definitions in Sourcify library
marcocastignoli Feb 6, 2025
1cb2aa4
Update error handling for bytecode fetching in Sourcify verification
marcocastignoli Feb 10, 2025
8df9015
Remove unnecessary compilationTarget deletion in SolidityCompilation
marcocastignoli Feb 10, 2025
488d562
Refactor bytecode matching method signature and remove unused context…
marcocastignoli Feb 10, 2025
a55ca31
Improve bytecode matching readability with descriptive variable names
marcocastignoli Feb 10, 2025
6126e53
Remove unused getter abiEncodedConstructorArguments in Verification c…
marcocastignoli Feb 10, 2025
ebfe9ab
Refactor Solidity settings type and improve bug handling in verification
marcocastignoli Feb 10, 2025
ed4fb93
Update SolidityBugType and improve error handling in verification tests
marcocastignoli Feb 10, 2025
bf73ff6
Renamed functions in Transformations.ts to use 'extract' prefix inste…
marcocastignoli Feb 11, 2025
232f0be
Simplify extra file input bug detection and remove redundant error ha…
marcocastignoli Feb 11, 2025
e29ad59
Refactor Solidity metadata and compiler settings types
marcocastignoli Feb 11, 2025
f0e0fe7
fixes for PR comments
marcocastignoli Feb 19, 2025
3de45a2
Validate the bytecode length for Solidity and Vyper compilations befo…
marcocastignoli Feb 19, 2025
4d4cb96
do not use existing transformations/values in `matchBytecode`.
marcocastignoli Feb 19, 2025
de425e2
Fix extra-file-input-bug at bytecode mismatch error
marcocastignoli Feb 24, 2025
db358c2
fix `should return null match when there is no perfect match and no a…
marcocastignoli Feb 24, 2025
0350c49
fix "maliciously verify with creation bytecode that startsWith the cr…
marcocastignoli Feb 24, 2025
30e5ee2
fixes after PR review
marcocastignoli Feb 25, 2025
a1f85fe
Improve source file reading and verification error handling
marcocastignoli Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions packages/lib-sourcify/src/Compilation/AbstractCompilation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
CompilationTarget,
CompiledContractCborAuxdata,
Metadata,
LinkReferences,
} from './CompilationTypes';
import {
ImmutableReferences,
Expand All @@ -17,7 +18,7 @@
VyperOutput,
VyperOutputContract,
} from './VyperTypes';
import { logInfo, logSilly, logWarn } from '../lib/logger';
import { logInfo, logSilly, logWarn } from '../logger';

export abstract class AbstractCompilation {
/**
Expand All @@ -28,14 +29,14 @@
abstract compilationTarget: CompilationTarget;
abstract jsonInput: SolidityJsonInput | VyperJsonInput;

metadata?: Metadata;
protected _metadata?: Metadata;
compilerOutput?: SolidityOutput | VyperOutput;

abstract auxdataStyle: AuxdataStyle;

/** Marks the positions of the CborAuxdata parts in the bytecode */
creationBytecodeCborAuxdata?: CompiledContractCborAuxdata;
runtimeBytecodeCborAuxdata?: CompiledContractCborAuxdata;
protected _creationBytecodeCborAuxdata?: CompiledContractCborAuxdata;
protected _runtimeBytecodeCborAuxdata?: CompiledContractCborAuxdata;

/**
* Recompiles the contract with the specified compiler settings
Expand Down Expand Up @@ -73,7 +74,7 @@
}

// We call getCompilationTarget() before logging because it can throw an error
const compilationTarget = this.getCompilationTarget();
const compilationTarget = this.compilationTargetContract;

const compilationEndTime = Date.now();
const compilationDuration = compilationEndTime - compilationStartTime;
Expand All @@ -89,7 +90,9 @@
return compilationTarget;
}

getCompilationTarget(): SolidityOutputContract | VyperOutputContract {
get compilationTargetContract():
| SolidityOutputContract
| VyperOutputContract {
if (!this.compilerOutput) {
logWarn('Compiler output is undefined');
throw new Error('Compiler output is undefined');
Expand All @@ -110,20 +113,36 @@
];
}

getCreationBytecode() {
return `0x${this.getCompilationTarget().evm.bytecode.object}`;
get creationBytecode() {
return `0x${this.compilationTargetContract.evm.bytecode.object}`;
}

getRuntimeBytecode() {
return `0x${this.getCompilationTarget().evm.deployedBytecode.object}`;
get runtimeBytecode() {
return `0x${this.compilationTargetContract.evm.deployedBytecode.object}`;
}

getMetadata(): Metadata {
if (!this.metadata) {
get metadata() {
if (!this._metadata) {
throw new Error('Metadata is not set');
}
return this.metadata;
return this._metadata;
}

abstract getImmutableReferences(): ImmutableReferences;
abstract get immutableReferences(): ImmutableReferences;
abstract get runtimeLinkReferences(): LinkReferences;
abstract get creationLinkReferences(): LinkReferences;

get creationBytecodeCborAuxdata(): CompiledContractCborAuxdata {
if (!this._creationBytecodeCborAuxdata) {
throw new Error('Creation bytecode cbor auxdata is not set');
}

Check warning on line 138 in packages/lib-sourcify/src/Compilation/AbstractCompilation.ts

View check run for this annotation

Codecov / codecov/patch

packages/lib-sourcify/src/Compilation/AbstractCompilation.ts#L137-L138

Added lines #L137 - L138 were not covered by tests
return this._creationBytecodeCborAuxdata;
}

get runtimeBytecodeCborAuxdata(): CompiledContractCborAuxdata {
if (!this._runtimeBytecodeCborAuxdata) {
throw new Error('Runtime bytecode cbor auxdata is not set');
}

Check warning on line 145 in packages/lib-sourcify/src/Compilation/AbstractCompilation.ts

View check run for this annotation

Codecov / codecov/patch

packages/lib-sourcify/src/Compilation/AbstractCompilation.ts#L144-L145

Added lines #L144 - L145 were not covered by tests
return this._runtimeBytecodeCborAuxdata;
}
}
48 changes: 14 additions & 34 deletions packages/lib-sourcify/src/Compilation/CompilationTypes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Abi } from 'abitype';
import { SoliditySettings } from './SolidityTypes';

Check warning on line 2 in packages/lib-sourcify/src/Compilation/CompilationTypes.ts

View check run for this annotation

Codecov / codecov/patch

packages/lib-sourcify/src/Compilation/CompilationTypes.ts#L2

Added line #L2 was not covered by tests

export interface LinkReferences {
[filePath: string]: {
Expand Down Expand Up @@ -75,6 +76,18 @@
userdoc: Userdoc;
}

// Metadata JSON's "settings" does have extra "compilationTarget" and its "libraries" field is in a different format
// ( libraries["MyContract.sol:Mycontract"]:"0xab..cd" vs libraries["MyContract.sol"]["MyContract"]:"0xab..cd")
export interface MetadataCompilerSettings
extends Omit<SoliditySettings, 'libraries' | 'outputSelection'> {
compilationTarget: {
[sourceName: string]: string;
};
libraries?: {
[index: string]: string;
};
}

Check warning on line 90 in packages/lib-sourcify/src/Compilation/CompilationTypes.ts

View check run for this annotation

Codecov / codecov/patch

packages/lib-sourcify/src/Compilation/CompilationTypes.ts#L79-L90

Added lines #L79 - L90 were not covered by tests
// Metadata type that reflects the metadata object from
// https://docs.soliditylang.org/en/latest/metadata.html
export interface Metadata {
Expand All @@ -84,40 +97,7 @@
};
language: string;
output: MetadataOutput;
settings: {
compilationTarget: {
[sourceName: string]: string;
};
evmVersion?: string;
libraries?: {
[index: string]: string;
};
metadata?: {
appendCBOR?: boolean;
bytecodeHash?: 'none' | 'ipfs' | 'bzzr0' | 'bzzr1';
useLiteralContent?: boolean;
};
optimizer?: {
details?: {
constantOptimizer?: boolean;
cse?: boolean;
deduplicate?: boolean;
inliner?: boolean;
jumpdestRemover?: boolean;
orderLiterals?: boolean;
peephole?: boolean;
yul?: boolean;
yulDetails?: {
optimizerSteps?: string;
stackAllocation?: boolean;
};
};
enabled: boolean;
runs: number;
};
viaIR?: boolean;
outputSelection?: any;
};
settings: MetadataCompilerSettings;

Check warning on line 100 in packages/lib-sourcify/src/Compilation/CompilationTypes.ts

View check run for this annotation

Codecov / codecov/patch

packages/lib-sourcify/src/Compilation/CompilationTypes.ts#L100

Added line #L100 was not covered by tests
sources: MetadataSourceMap;
version: number;
}
Expand Down
57 changes: 35 additions & 22 deletions packages/lib-sourcify/src/Compilation/SolidityCompilation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
SolidityOutput,
SolidityOutputContract,
} from './SolidityTypes';
import { CompilationTarget } from './CompilationTypes';
import { CompilationTarget, LinkReferences } from './CompilationTypes';
import {
findAuxdataPositions,
findAuxdatasInLegacyAssembly,
Expand All @@ -22,7 +22,6 @@ export class SolidityCompilation extends AbstractCompilation {
declare compileAndReturnCompilationTarget: (
forceEmscripten: boolean,
) => Promise<SolidityOutputContract>;
declare getCompilationTarget: () => SolidityOutputContract;

// Specify the auxdata style, used for extracting the auxdata from the compiler output
readonly auxdataStyle: AuxdataStyle.SOLIDITY = AuxdataStyle.SOLIDITY;
Expand Down Expand Up @@ -91,31 +90,32 @@ export class SolidityCompilation extends AbstractCompilation {
public async generateCborAuxdataPositions(forceEmscripten = false) {
// Auxdata array extracted from the compiler's `legacyAssembly` field
const auxdatasFromCompilerOutput = findAuxdatasInLegacyAssembly(
this.getCompilationTarget().evm.legacyAssembly,
(this.compilationTargetContract as SolidityOutputContract).evm
.legacyAssembly,
);

// Case: there is not auxadata
if (auxdatasFromCompilerOutput.length === 0) {
this.creationBytecodeCborAuxdata = {};
this.runtimeBytecodeCborAuxdata = {};
this._creationBytecodeCborAuxdata = {};
this._runtimeBytecodeCborAuxdata = {};
return true;
}

// Case: there is only one auxdata, no need to recompile
// Case: there is only one auxdata, no need to recompile if we find both runtime and creation auxdata at the end of the bytecode (creation auxdata can be in a different place)
if (auxdatasFromCompilerOutput.length === 1) {
// Extract the auxdata from the end of the recompiled runtime bytecode
const [, runtimeAuxdataCbor, runtimeCborLengthHex] = splitAuxdata(
this.getRuntimeBytecode(),
this.runtimeBytecode,
this.auxdataStyle,
);

const auxdataFromRawRuntimeBytecode = `${runtimeAuxdataCbor}${runtimeCborLengthHex}`;

// we divide by 2 because we store the length in bytes (without 0x)
this.runtimeBytecodeCborAuxdata = {
this._runtimeBytecodeCborAuxdata = {
'1': {
offset:
this.getRuntimeBytecode().substring(2).length / 2 -
this.runtimeBytecode.substring(2).length / 2 -
parseInt(runtimeCborLengthHex, 16) -
2, // bytecode has 2 bytes of cbor length prefix at the end
value: `0x${auxdataFromRawRuntimeBytecode}`,
Expand All @@ -124,18 +124,18 @@ export class SolidityCompilation extends AbstractCompilation {

// Try to extract the auxdata from the end of the recompiled creation bytecode
const [, creationAuxdataCbor, creationCborLengthHex] = splitAuxdata(
this.getCreationBytecode(),
this.creationBytecode,
this.auxdataStyle,
);

// If we can find the auxdata at the end of the bytecode return; otherwise continue with `generateEditedContract`
if (creationAuxdataCbor) {
const auxdataFromRawCreationBytecode = `${creationAuxdataCbor}${creationCborLengthHex}`;
// we divide by 2 because we store the length in bytes (without 0x)
this.creationBytecodeCborAuxdata = {
this._creationBytecodeCborAuxdata = {
'1': {
offset:
this.getCreationBytecode().substring(2).length / 2 -
this.creationBytecode.substring(2).length / 2 -
parseInt(creationCborLengthHex, 16) -
2, // bytecode has 2 bytes of cbor length prefix at the end
value: `0x${auxdataFromRawCreationBytecode}`,
Expand All @@ -145,7 +145,7 @@ export class SolidityCompilation extends AbstractCompilation {
}
}

// Case: multiple auxdatas or failing creation auxdata,
// Case: multiple auxdatas or creation auxdata not found at the end of the bytecode,
// we need to recompile with a slightly edited file to check the differences
const editedContractCompilerOutput = await this.generateEditedContract({
version: this.compilerVersion,
Expand All @@ -160,19 +160,19 @@ export class SolidityCompilation extends AbstractCompilation {
const editedContractAuxdatasFromCompilerOutput =
findAuxdatasInLegacyAssembly(editedContract.evm.legacyAssembly);

// Potentially we already found runtimeBytecodeCborAuxdata in the case of failing creation auxdata
// Potentially we already found runtimeBytecodeCborAuxdata in the case of creation auxdata not found at the end of the bytecode
// so no need to call `findAuxdataPositions`
if (this.runtimeBytecodeCborAuxdata === undefined) {
this.runtimeBytecodeCborAuxdata = findAuxdataPositions(
this.getRuntimeBytecode(),
if (this._runtimeBytecodeCborAuxdata === undefined) {
this._runtimeBytecodeCborAuxdata = findAuxdataPositions(
this.runtimeBytecode,
`0x${editedContract.evm.deployedBytecode.object}`,
auxdatasFromCompilerOutput,
editedContractAuxdatasFromCompilerOutput,
);
}

this.creationBytecodeCborAuxdata = findAuxdataPositions(
this.getCreationBytecode(),
this._creationBytecodeCborAuxdata = findAuxdataPositions(
this.creationBytecode,
`0x${editedContract.evm.bytecode.object}`,
auxdatasFromCompilerOutput,
editedContractAuxdatasFromCompilerOutput,
Expand All @@ -184,11 +184,24 @@ export class SolidityCompilation extends AbstractCompilation {
public async compile(forceEmscripten = false) {
const contract =
await this.compileAndReturnCompilationTarget(forceEmscripten);
this.metadata = JSON.parse(contract.metadata.trim());
this._metadata = JSON.parse(contract.metadata.trim());
}

getImmutableReferences(): ImmutableReferences {
const compilationTarget = this.getCompilationTarget();
get immutableReferences(): ImmutableReferences {
const compilationTarget = this
.compilationTargetContract as SolidityOutputContract;
return compilationTarget.evm.deployedBytecode.immutableReferences || {};
}

get runtimeLinkReferences(): LinkReferences {
const compilationTarget = this
.compilationTargetContract as SolidityOutputContract;
return compilationTarget.evm.deployedBytecode.linkReferences || {};
}

get creationLinkReferences(): LinkReferences {
const compilationTarget = this
.compilationTargetContract as SolidityOutputContract;
return compilationTarget.evm.bytecode.linkReferences || {};
}
}
5 changes: 2 additions & 3 deletions packages/lib-sourcify/src/Compilation/SolidityTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
timeout?: number;
}

interface Settings {
export interface SoliditySettings {

Check warning on line 81 in packages/lib-sourcify/src/Compilation/SolidityTypes.ts

View check run for this annotation

Codecov / codecov/patch

packages/lib-sourcify/src/Compilation/SolidityTypes.ts#L81

Added line #L81 was not covered by tests
stopAfter?: string;
remappings?: string[];
optimizer?: Optimizer;
Expand All @@ -89,13 +89,12 @@
libraries?: Libraries;
outputSelection: OutputSelection;
modelChecker?: ModelChecker;
compilationTarget?: string;
}

export interface SolidityJsonInput {
language: string;
sources: Sources;
settings: Settings;
settings: SoliditySettings;

Check warning on line 97 in packages/lib-sourcify/src/Compilation/SolidityTypes.ts

View check run for this annotation

Codecov / codecov/patch

packages/lib-sourcify/src/Compilation/SolidityTypes.ts#L97

Added line #L97 was not covered by tests
}

interface SolidityOutputError {
Expand Down
Loading