Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3265 from trufflesuite/eradicate-hashes
Browse files Browse the repository at this point in the history
Enhancement: Broader contract recognition (treat all contracts the way we treated externally-downloaded ones)
  • Loading branch information
haltman-at authored Nov 4, 2020
2 parents 8f5808a + be9b97e commit 3ba09e4
Show file tree
Hide file tree
Showing 39 changed files with 353 additions and 378 deletions.
20 changes: 10 additions & 10 deletions packages/codec/lib/abi-data/allocate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,8 @@ function allocateCalldataAndReturndata(
abiAllocations: AbiAllocations,
compilationId: string,
compiler: Compiler.CompilerVersion | undefined,
constructorContext?: Contexts.DecoderContext,
deployedContext?: Contexts.DecoderContext
constructorContext?: Contexts.Context,
deployedContext?: Contexts.Context
): CalldataAndReturndataAllocation | undefined {
//first: determine the corresponding function node
//(simultaneously: determine the offset)
Expand Down Expand Up @@ -723,8 +723,8 @@ function allocateEvent(
function getCalldataAllocationsForContract(
abi: Abi.Abi,
contractNode: Ast.AstNode,
constructorContext: Contexts.DecoderContext,
deployedContext: Contexts.DecoderContext,
constructorContext: Contexts.Context,
deployedContext: Contexts.Context,
referenceDeclarations: Ast.AstNodes,
userDefinedTypes: Format.Types.TypesById,
abiAllocations: AbiAllocations,
Expand Down Expand Up @@ -806,10 +806,10 @@ function getCalldataAllocationsForContract(
}

function defaultConstructorAllocation(
constructorContext: Contexts.DecoderContext,
constructorContext: Contexts.Context,
contractNode: Ast.AstNode | undefined,
referenceDeclarations: Ast.AstNodes,
deployedContext?: Contexts.DecoderContext
deployedContext?: Contexts.Context
): CalldataAndReturndataAllocation | undefined {
if (!constructorContext) {
return undefined;
Expand All @@ -833,7 +833,7 @@ function defaultConstructorAllocation(

//note: context should be deployed context!
function constructorOutputAllocation(
context: Contexts.DecoderContext | undefined,
context: Contexts.Context | undefined,
contractNode: Ast.AstNode | undefined,
referenceDeclarations: Ast.AstNodes,
allocationMode: DecodingMode
Expand Down Expand Up @@ -1009,7 +1009,7 @@ export function getEventAllocations(
let individualAllocations: {
[contractKey: string]: {
[selector: string]: {
context: Contexts.DecoderContext;
context: Contexts.Context;
contractNode: Ast.AstNode;
allocationTemporary: EventAllocationTemporary;
compilationId: string;
Expand All @@ -1019,7 +1019,7 @@ export function getEventAllocations(
let groupedAllocations: {
[contractKey: string]: {
[selector: string]: {
context: Contexts.DecoderContext;
context: Contexts.Context;
contractNode: Ast.AstNode;
allocationsTemporary: EventAllocationTemporary[];
};
Expand Down Expand Up @@ -1261,7 +1261,7 @@ function findNodeAndContract(
}

function makeContractKey(
context: Contexts.DecoderContext | undefined,
context: Contexts.Context | undefined,
id: number,
compilationId: string
): string {
Expand Down
4 changes: 2 additions & 2 deletions packages/codec/lib/abi-data/allocate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import * as Format from "@truffle/codec/format";
export interface ContractAllocationInfo {
abi?: Abi.Abi; //needed for events & calldata
contractNode: Ast.AstNode; //needed for all 3
deployedContext?: Contexts.DecoderContext; //needed for events & calldata
constructorContext?: Contexts.DecoderContext; //needed for calldata
deployedContext?: Contexts.Context; //needed for events & calldata
constructorContext?: Contexts.Context; //needed for calldata
immutableReferences?: ImmutableReferences; //needed for state
compiler: Compiler.CompilerVersion; //needed for all 3
compilationId?: string; //needed for all 3
Expand Down
4 changes: 2 additions & 2 deletions packages/codec/lib/basic/decode/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ function* decodeContractAndContext(
address
};
let code = Conversion.toHexString(codeBytes);
let context = Contexts.Utils.findDecoderContext(info.contexts, code);
let context = Contexts.Utils.findContext(info.contexts, code);
if (context !== null) {
return {
context,
Expand Down Expand Up @@ -779,5 +779,5 @@ function checkPaddingSigned(bytes: Uint8Array, length: number): boolean {
*/
export interface ContractInfoAndContext {
contractInfo: Format.Values.ContractValueInfo;
context?: Contexts.DecoderContext;
context?: Contexts.Context;
}
9 changes: 0 additions & 9 deletions packages/codec/lib/compilations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,6 @@ export interface Compilation {
* specified on each source and contract, but please don't actually do that.
*/
compiler?: Compiler.CompilerVersion;
/**
* A flag intended for internal use to indicate that this compilation is not
* part of the user's Truffle project but rather is compiled from
* temporarily-downloaded external sources. This flag was only originally
* intended to be used for Solidity or Yul, hence the name; but it should be
* OK to set this for externally-downloaded sources regardless of their
* language.
*/
externalSolidity?: boolean;
}

/**
Expand Down
21 changes: 7 additions & 14 deletions packages/codec/lib/compilations/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@ import { Compilation, Contract, Source } from "./types";

export function shimCompilations(
inputCompilations: CompilerCompilation[],
shimmedCompilationIdPrefix = "shimmedcompilation",
externalSolidity = false
shimmedCompilationIdPrefix = "shimmedcompilation"
): Compilation[] {
return inputCompilations.map(
({ contracts, sourceIndexes }, compilationIndex) =>
shimContracts(
contracts,
sourceIndexes,
`${shimmedCompilationIdPrefix}Number(${compilationIndex})`,
externalSolidity
`${shimmedCompilationIdPrefix}Number(${compilationIndex})`
)
);
}
Expand All @@ -37,12 +35,9 @@ export function shimCompilations(
export function shimArtifacts(
artifacts: (Artifact | CompiledContract)[],
files?: string[],
shimmedCompilationId: string = "shimmedcompilation",
externalSolidity: boolean = false
shimmedCompilationId = "shimmedcompilation"
): Compilation[] {
return [
shimContracts(artifacts, files, shimmedCompilationId, externalSolidity)
];
return [shimContracts(artifacts, files, shimmedCompilationId)];
}

/**
Expand All @@ -52,8 +47,7 @@ export function shimArtifacts(
export function shimContracts(
artifacts: (Artifact | CompiledContract)[],
files?: string[],
shimmedCompilationId: string = "shimmedcompilation",
externalSolidity: boolean = false
shimmedCompilationId: string = "shimmedcompilation"
): Compilation {
let contracts: Contract[] = [];
let sources: Source[] = [];
Expand Down Expand Up @@ -171,9 +165,8 @@ export function shimContracts(
unreliableSourceOrder,
sources,
contracts,
compiler,
externalSolidity
};
compiler
}
}

function sourceIndexForAst(ast: Ast.AstNode): number | undefined {
Expand Down
20 changes: 7 additions & 13 deletions packages/codec/lib/contexts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,11 @@ import * as Common from "@truffle/codec/common";
import * as Compiler from "@truffle/codec/compiler";
import { ImmutableReferences } from "@truffle/contract-schema/spec";

export type Contexts = DecoderContexts | DebuggerContexts;

export type Context = DecoderContext | DebuggerContext;

export interface DecoderContexts {
[context: string]: DecoderContext;
}

export interface DebuggerContexts {
[context: string]: DebuggerContext;
export interface Contexts {
[context: string]: Context;
}

export interface DecoderContext {
export interface Context {
context: string; //The context hash
binary: string; //this should (for now) be the normalized binary, with "."s
//in place of link references or other variable parts; this will probably
Expand All @@ -25,6 +17,7 @@ export interface DecoderContext {
immutableReferences?: ImmutableReferences; //never included for a constructor
contractName?: string;
contractId?: number;
linearizedBaseContracts?: number[];
contractKind?: Common.ContractKind; //note: should never be "interface"
abi?: AbiData.FunctionAbiBySelectors;
payable?: boolean;
Expand All @@ -35,9 +28,10 @@ export interface DecoderContext {
};
compiler?: Compiler.CompilerVersion;
compilationId?: string;
externalSolidity?: boolean; //please only set for Solidity contracts!
}

//NOTE: this is being kept for reference (the debugger is JS and can't import
//types), but we don't actually use this type anywhere anymore.
export interface DebuggerContext {
context: string; //The context hash
binary: string; //this should (for now) be the normalized binary, with "."s
Expand All @@ -47,12 +41,12 @@ export interface DebuggerContext {
immutableReferences?: ImmutableReferences; //never included for a constructor
contractName?: string;
contractId?: number;
linearizedBaseContracts?: number[];
contractKind?: Common.ContractKind; //note: should never be "interface"
abi?: Abi.Abi;
sourceMap?: string;
primarySource?: number;
compiler?: Compiler.CompilerVersion;
compilationId?: string;
payable?: boolean;
externalSolidity?: boolean; //please only set for Solidity contracts!
}
67 changes: 29 additions & 38 deletions packages/codec/lib/contexts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,31 @@ import debugModule from "debug";
const debug = debugModule("codec:contexts:utils");

import * as Evm from "@truffle/codec/evm";
import {
DecoderContexts,
DecoderContext,
Context,
Contexts,
DebuggerContexts
} from "./types";
import { Context, Contexts } from "./types";
import escapeRegExp from "lodash.escaperegexp";
const cbor = require("borc"); //importing this untyped, sorry!

//I split these next two apart because the type system was giving me trouble
export function findDecoderContext(
contexts: DecoderContexts,
export function findContext(
contexts: Contexts,
binary: string
): DecoderContext | null {
let context = Object.values(contexts).find(context =>
): Context | null {
const matchingContexts = Object.values(contexts).filter(context =>
matchContext(context, binary)
);
return context !== undefined ? context : null;
}

export function findDebuggerContext(
contexts: DebuggerContexts,
binary: string
): string | null {
let context = Object.values(contexts).find(context =>
matchContext(context, binary)
//rather than just pick an arbitrary matching context, we're going
//to pick one that isn't a descendant of any of the others.
//(if there are multiple of *those*, then yeah it's arbitrary.)
const context = matchingContexts.find(
descendant => !matchingContexts.some(ancestor =>
descendant.compilationId === ancestor.compilationId &&
descendant.linearizedBaseContracts &&
ancestor.contractId !== undefined &&
descendant.linearizedBaseContracts.slice(1).includes(ancestor.contractId)
//we do slice one because everything is an an ancestor of itself; we only
//care about *proper* ancestors
)
);
return context !== undefined ? context.context : null;
return context || null;
}

export function matchContext(context: Context, givenBinary: string): boolean {
Expand Down Expand Up @@ -165,16 +161,13 @@ export function normalizeContexts(contexts: Contexts): Contexts {

debug("immutables complete");

//one last step: if externalSolidity is set, we'll allow the CBOR to vary,
//aside from the length (note: ideally here we would *only* dot-out the
//metadata hash part of the CBOR, but, well, it's not worth the trouble
//to detect that; doing that could potentially get pretty involved)
//NOTE: this will cause a problem with Solidity versions 0.4.6 and earlier,
//but it's not worth the trouble to detect that either, because we really
//don't support Solidity versions that old
//note that the externalSolidity option should *only* be set for Solidity contracts!
//one last step: where there's CBOR with a metadata hash, we'll allow the
//CBOR to vary, aside from the length (note: ideally here we would *only*
//dot-out the metadata hash part of the CBOR, but, well, it's not worth the
//trouble to detect that; doing that could potentially get pretty involved)
//note that if the code isn't Solidity, that's fine -- we just won't get
//valid CBOR and will not end up adding to our list of regular expressions
const externalCborInfo = Object.values(newContexts)
.filter(context => context.externalSolidity)
.map(context => extractCborInfo(context.binary))
.filter(
cborSegment => cborSegment !== null && isCborWithHash(cborSegment.cbor)
Expand All @@ -183,14 +176,12 @@ export function normalizeContexts(contexts: Contexts): Contexts {
input: new RegExp(cborInfo.cborSegment, "g"), //hex string so no need for escape
output: "..".repeat(cborInfo.cborLength) + cborInfo.cborLengthHex
}));
//HACK: we will replace *every* occurrence of *every* external CBOR occurring in
//*every* external Solidity context, in order to cover created contracts
//(including if there are multiple or recursive ones)
//HACK: we will replace *every* occurrence of *every* external CBOR occurring
//in *every* context, in order to cover created contracts (including if there
//are multiple or recursive ones)
for (let context of Object.values(newContexts)) {
if (context.externalSolidity) {
for (let { input, output } of cborRegexps) {
context.binary = context.binary.replace(input, output);
}
for (let { input, output } of cborRegexps) {
context.binary = context.binary.replace(input, output);
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/codec/lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ export function* decodeEvent(
address
};
const codeAsHex = Conversion.toHexString(codeBytes);
const contractContext = Contexts.Utils.findDecoderContext(
const contractContext = Contexts.Utils.findContext(
info.contexts,
codeAsHex
);
Expand Down Expand Up @@ -669,7 +669,7 @@ function* decodeBytecode(
> {
let decodingMode: DecodingMode = "full"; //as always, degrade as necessary
const bytecode = Conversion.toHexString(info.state.returndata);
const context = Contexts.Utils.findDecoderContext(info.contexts, bytecode);
const context = Contexts.Utils.findContext(info.contexts, bytecode);
if (!context) {
return {
kind: "unknownbytecode" as const,
Expand Down
4 changes: 2 additions & 2 deletions packages/codec/lib/evm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export interface EvmInfo {
mappingKeys?: Storage.Slot[];
userDefinedTypes?: Format.Types.TypesById;
allocations: AllocationInfo;
contexts?: Contexts.DecoderContexts;
currentContext?: Contexts.DecoderContext;
contexts?: Contexts.Contexts;
currentContext?: Contexts.Context;
internalFunctionsTable?: InternalFunctions;
}

Expand Down
10 changes: 5 additions & 5 deletions packages/contract-tests/test/customoptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ var contract = require("@truffle/contract");
describe("Custom options", function () {
it("allows custom options", function () {
var Example = contract({
"contractName": "Example",
"abi": [],
"binary": "0xabcdef",
"address": "0xe6e1652a0397e078f434d6dda181b218cfd42e01",
"network_id": 3,
contractName: "Example",
abi: [],
binary: "0xabcdef",
address: "0xe6e1652a0397e078f434d6dda181b218cfd42e01",
network_id: 3,
"x-from-dependency": "somedep"
});
assert.equal(Example["x-from-dependency"], "somedep");
Expand Down
Loading

0 comments on commit 3ba09e4

Please sign in to comment.