Skip to content

Commit 01dd7ca

Browse files
committed
Add linkReferences map as optional parameter to linkBytecode function
1 parent c1dec49 commit 01dd7ca

File tree

2 files changed

+38
-16
lines changed

2 files changed

+38
-16
lines changed

linker.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,24 @@ function libraryHashPlaceholder (fullyQualifiedLibraryName) {
2727
*
2828
* @param address Address to replace placeholders with. Must be the right length.
2929
* It will **not** be padded with zeros if too short.
30+
*
31+
* @param linkReferences A optional mapping of libraries to lists of placeholder positions in the binary.
3032
*/
31-
function replacePlaceholder (bytecode, label, address) {
33+
function replacePlaceholder (bytecode: string, label: string, address: string, linkReferences?: LinkReferences): string {
34+
// Try to find link references if `linkReferences` is not provided
35+
if (!linkReferences) {
36+
linkReferences = findLinkReferences(bytecode);
37+
}
38+
3239
// truncate to 36 characters
3340
const truncatedName = label.slice(0, 36);
34-
const libLabel = `__${truncatedName.padEnd(36, '_')}__`;
3541

36-
while (bytecode.indexOf(libLabel) >= 0) {
37-
bytecode = bytecode.replace(libLabel, address);
42+
if (linkReferences && linkReferences[truncatedName]) {
43+
linkReferences[truncatedName].forEach(function (reference) {
44+
const start = reference.start * 2;
45+
const end = (reference.start + reference.length) * 2;
46+
bytecode = bytecode.replace(bytecode.substring(start, end), address);
47+
});
3848
}
3949

4050
return bytecode;
@@ -55,10 +65,12 @@ function replacePlaceholder (bytecode, label, address) {
5565
* @param libraries Mapping between fully qualified library names and the hex-encoded
5666
* addresses they should be replaced with. Addresses shorter than 40 characters are automatically padded with zeros.
5767
*
68+
* @param linkReferences A optional mapping of libraries to lists of placeholder positions in the binary.
69+
*
5870
* @returns bytecode Hex-encoded bytecode string with placeholders replaced with addresses.
5971
* Note that some placeholders may remain in the bytecode if `libraries` does not provide addresses for all of them.
6072
*/
61-
function linkBytecode (bytecode: string, libraries: LibraryAddresses): string {
73+
function linkBytecode (bytecode: string, libraries: LibraryAddresses, linkReferences?: LinkReferences): string {
6274
assert(typeof bytecode === 'string');
6375
assert(typeof libraries === 'object');
6476

@@ -103,8 +115,8 @@ function linkBytecode (bytecode: string, libraries: LibraryAddresses): string {
103115
// remove 0x prefix
104116
hexAddress = hexAddress.slice(2).padStart(40, '0');
105117

106-
bytecode = replacePlaceholder(bytecode, libraryName, hexAddress);
107-
bytecode = replacePlaceholder(bytecode, libraryHashPlaceholder(libraryName), hexAddress);
118+
bytecode = replacePlaceholder(bytecode, libraryName, hexAddress, linkReferences);
119+
bytecode = replacePlaceholder(bytecode, libraryHashPlaceholder(libraryName), hexAddress, linkReferences);
108120
}
109121

110122
return bytecode;

test/linker.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,20 +172,30 @@ tape('Linking', function (t) {
172172
'lib.sol': 'library L { function f() public returns (uint) { return 7; } }',
173173
'cont.sol': 'import "lib.sol"; contract x { function g() public { L.f(); } }'
174174
*/
175-
var bytecode = '608060405234801561001057600080fd5b5061011f806100206000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e2179b8e146044575b600080fd5b348015604f57600080fd5b5060566058565b005b73__lib.sol:L_____________________________6326121ff06040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801560b757600080fd5b505af415801560ca573d6000803e3d6000fd5b505050506040513d602081101560df57600080fd5b8101908080519060200190929190505050505600a165627a7a72305820ea2f6353179c181d7162544d637b7fe2d9e8da9803a0e2d9eafc2188d1d59ee30029';
176-
bytecode = linker.linkBytecode(bytecode, { 'lib.sol:L': '0x123456' }, { 'lib.sol:L': [ { start: 122, length: 20 } ] });
175+
let bytecode = '608060405234801561001057600080fd5b5061011f806100206000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e2179b8e146044575b600080fd5b348015604f57600080fd5b5060566058565b005b73__lib.sol:L_____________________________6326121ff06040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801560b757600080fd5b505af415801560ca573d6000803e3d6000fd5b505050506040513d602081101560df57600080fd5b8101908080519060200190929190505050505600a165627a7a72305820ea2f6353179c181d7162544d637b7fe2d9e8da9803a0e2d9eafc2188d1d59ee30029';
176+
bytecode = linker.linkBytecode(bytecode, { 'lib.sol:L': '0x123456' }, { 'lib.sol:L': [{ start: 122, length: 20 }] });
177177
st.ok(bytecode.indexOf('_') < 0);
178178
st.end();
179179
});
180180

181-
t.test('link properly using manual reference search', function (st) {
182-
/*
183-
'lib.sol': 'library L { function f() public returns (uint) { return 7; } }',
184-
'cont.sol': 'import "lib.sol"; contract x { function g() public { L.f(); } }'
185-
*/
186-
var bytecode = '608060405234801561001057600080fd5b5061011f806100206000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e2179b8e146044575b600080fd5b348015604f57600080fd5b5060566058565b005b73__lib.sol:L_____________________________6326121ff06040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801560b757600080fd5b505af415801560ca573d6000803e3d6000fd5b505050506040513d602081101560df57600080fd5b8101908080519060200190929190505050505600a165627a7a72305820ea2f6353179c181d7162544d637b7fe2d9e8da9803a0e2d9eafc2188d1d59ee30029';
187-
bytecode = linker.linkBytecode(bytecode, { 'lib.sol:L': '0x123456' }, {});
181+
t.test('link properly by providing two references with same library name', function (st) {
182+
let bytecode = '6060604052341561000f57600080fd5b61011a8061001e6000396000f30060606040526004361060255763ffffffff60e060020a60003504166326121ff08114602a575b600080fd5b3415603457600080fd5b603a603c565b005b73__lib2.sol:L____________________________6326121ff06040518163ffffffff1660e060020a02815260040160006040518083038186803b1515608157600080fd5b6102c65a03f41515609157600080fd5b50505073__lib2.sol:L____________________________6326121ff06040518163ffffffff1660e060020a02815260040160006040518083038186803b151560d957600080fd5b6102c65a03f4151560e957600080fd5b5050505600a165627a7a72305820fdfb8eab411d7bc86d7dfbb0c985c30bebf1cc105dc5b807291551b3d5aa29d90029';
183+
bytecode = linker.linkBytecode(bytecode, { 'lib2.sol:L': '0x123456' }, { 'lib2.sol:L': [{ start: 92, length: 20 }, { start: 180, length: 20 }] });
184+
st.ok(bytecode.indexOf('_') < 0);
185+
st.end();
186+
});
187+
188+
t.test('link properly by providing multiple references for multiple libraries', function (st) {
189+
let bytecode = '6060604052341561000f57600080fd5b61011a8061001e6000396000f30060606040526004361060255763ffffffff60e060020a60003504166326121ff08114602a575b600080fd5b3415603457600080fd5b603a603c565b005b73__lib2.sol:Lx___________________________6326121ff06040518163ffffffff1660e060020a02815260040160006040518083038186803b1515608157600080fd5b6102c65a03f41515609157600080fd5b50505073__lib2.sol:Lx___________________________6326121ff06040518163ffffffff1660e060020a02815260040160006040518083038186803b151560d957600080fd5b6102c65a03f4151560e957600080__lib1.sol:L____________________________411d7bc86d7dfbb0c985c30bebf1cc105dc5b807291551b3d5aa29d90029';
190+
bytecode = linker.linkBytecode(bytecode, { 'lib1.sol:L': '0x123456', 'lib2.sol:Lx': '0x789012' }, { 'lib2.sol:Lx': [{ start: 92, length: 20 }, { start: 180, length: 20 }], 'lib1.sol:L': [{ start: 262, length: 20 }] });
188191
st.ok(bytecode.indexOf('_') < 0);
189192
st.end();
190193
});
194+
195+
t.test('linker fails if wrong link references is provided', function (st) {
196+
let bytecode = '608060405234801561001057600080fd5b5061011f806100206000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e2179b8e146044575b600080fd5b348015604f57600080fd5b5060566058565b005b73__lib.sol:L_____________________________6326121ff06040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801560b757600080fd5b505af415801560ca573d6000803e3d6000fd5b505050506040513d602081101560df57600080fd5b8101908080519060200190929190505050505600a165627a7a72305820ea2f6353179c181d7162544d637b7fe2d9e8da9803a0e2d9eafc2188d1d59ee30029';
197+
bytecode = linker.linkBytecode(bytecode, { 'lib1.sol:L': '0x123456' }, {});
198+
st.ok(bytecode.indexOf('_') >= 0);
199+
st.end();
200+
});
191201
});

0 commit comments

Comments
 (0)