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

Commit

Permalink
Change to external link references format
Browse files Browse the repository at this point in the history
- Convert (deployedB|b)ytecode to object `{ bytes, linkReferences }`
- Remove 0x prefix from bytes
- Use zeroes instead of whatever solc uses in the bytes representation
- Convert link reference format to { offsets, name, length }
- Move __LibraryName___...___ nonsense into the legacy shims
  • Loading branch information
gnidan committed Jun 24, 2019
1 parent 4633cbc commit eadb547
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 30 deletions.
32 changes: 30 additions & 2 deletions packages/truffle-compile/legacy/shims.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,36 @@ function shimContract(contract) {
};
}

function shimBytecode(bytecode) {
return bytecode;
function shimBytecode({ bytes, linkReferences }) {
linkReferences = linkReferences || [];

// inline link references - start by flattening the offsets
const flattenedLinkReferences = linkReferences
// map each link ref to array of link refs with only one offset
.map(({ offsets, length, name }) =>
offsets.map(offset => ({ offset, length, name }))
)
// flatten
.reduce((a, b) => [...a, ...b], []);

// then overwite bytes with link reference
bytes = flattenedLinkReferences.reduce((bytes, { offset, name, length }) => {
// length is a byte offset
const characterLength = length * 2;

let linkId = `__${name.slice(0, characterLength - 2)}`;
while (linkId.length < characterLength) {
linkId += "_";
}

const start = offset * 2;

return `${bytes.substring(0, start)}${linkId}${bytes.substring(
start + characterLength
)}`;
}, bytes);

return `0x${bytes}`;
}

module.exports = {
Expand Down
64 changes: 36 additions & 28 deletions packages/truffle-compile/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,13 +333,13 @@ function processContracts({
deployedSourceMap,
ast,
legacyAST,
bytecode: replaceAllLinkReferences({
bytecode,
linkReferences
bytecode: zeroLinkReferences({
bytes: bytecode,
linkReferences: formatLinkReferences(linkReferences)
}),
deployedBytecode: replaceAllLinkReferences({
bytecode: deployedBytecode,
linkReferences: deployedLinkReferences
deployedBytecode: zeroLinkReferences({
bytes: deployedBytecode,
linkReferences: formatLinkReferences(deployedLinkReferences)
}),
compiler: {
name: "solc",
Expand Down Expand Up @@ -385,42 +385,50 @@ function orderABI({ abi, contractName, ast }) {
];
}

function replaceAllLinkReferences({ bytecode, linkReferences }) {
function formatLinkReferences(linkReferences) {
// convert to flat list
const libraryLinkReferences = Object.values(linkReferences)
.map(fileLinks =>
Object.entries(fileLinks).map(([libraryName, links]) => ({
libraryName,
Object.entries(fileLinks).map(([name, links]) => ({
name,
links
}))
)
.reduce((a, b) => [...a, ...b], []);

const unprefixed = libraryLinkReferences.reduce(
(bytecode, { libraryName, links }) =>
replaceLinkReferences(bytecode, links, libraryName),
bytecode
);

return `0x${unprefixed}`;
// convert to { offsets, length, name } format
return libraryLinkReferences.map(({ name, links }) => ({
offsets: links.map(({ start }) => start),
length: links[0].length, // HACK just assume they're going to be the same
name
}));
}

function replaceLinkReferences(bytecode, linkReferences, libraryName) {
var linkId = "__" + libraryName;
// takes linkReferences in output format (not Solidity's format)
function zeroLinkReferences({ bytes, linkReferences }) {
// inline link references - start by flattening the offsets
const flattenedLinkReferences = linkReferences
// map each link ref to array of link refs with only one offset
.map(({ offsets, length, name }) =>
offsets.map(offset => ({ offset, length, name }))
)
// flatten
.reduce((a, b) => [...a, ...b], []);

while (linkId.length < 40) {
linkId += "_";
}
// then overwite bytes with zeroes
bytes = flattenedLinkReferences.reduce((bytes, { offset, length }) => {
// length is a byte offset
const characterLength = length * 2;
const start = offset * 2;

linkReferences.forEach(function(ref) {
// ref.start is a byte offset. Convert it to character offset.
var start = ref.start * 2 + 2;
const zeroes = "0".repeat(characterLength);

bytecode =
bytecode.substring(0, start) + linkId + bytecode.substring(start + 40);
});
return `${bytes.substring(0, start)}${zeroes}${bytes.substring(
start + characterLength
)}`;
}, bytes);

return bytecode;
return { bytes, linkReferences };
}

/**
Expand Down
73 changes: 73 additions & 0 deletions packages/truffle-compile/test/legacy/shims.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const { assert } = require("chai");

const { shimBytecode } = require("truffle-compile/legacy/shims");

describe("shimBytecode", () => {
it("prepends 0x", function() {
const bytes = "ffffffff";

assert.equal(shimBytecode({ bytes }), `0x${bytes}`);
});

it("inlines an external link reference into underscores format", function() {
const bytecode = {
// 0 1 2 3 4 5 6 7 8 9
bytes: "00000000000000000000",
linkReferences: [
{
offsets: [1],
length: 8,
name: "hello"
}
]
};

// 0 1 2 3 4 5 6 7 8 9
const expected = "0x00__hello_________00";

assert.equal(shimBytecode(bytecode), expected);
});

it("inlines a link reference with multiple offsets", function() {
const bytecode = {
// 0 1 2 3 4 5 6 7 8 9
bytes: "00000000000000000000",
linkReferences: [
{
offsets: [0, 5],
length: 4,
name: "hi"
}
]
};

// 0 1 2 3 4 5 6 7 8 9
const expected = "0x__hi____00__hi____00";

assert.equal(shimBytecode(bytecode), expected);
});

it("inlines two different link references", function() {
const bytecode = {
// 0 1 2 3 4 5 6 7 8 9
bytes: "00000000000000000000",
linkReferences: [
{
offsets: [0],
length: 4,
name: "hi"
},
{
offsets: [5],
length: 4,
name: "there"
}
]
};

// 0 1 2 3 4 5 6 7 8 9
const expected = "0x__hi____00__there_00";

assert.equal(shimBytecode(bytecode), expected);
});
});

0 comments on commit eadb547

Please sign in to comment.