Summary
To deploy your library and contract code using geth
, you will have to:
Deploy your LinkedList
library code and note the address it is deployed to.
Replace the __LinkedList___...___
text in your Array
code with the LinkedLibrary
deployment address and deploy the code.
Some other alternatives:
Create an SSH tunnel between your remote server and your local machine so you can access your remote server's geth
RPC port from your local machine. Then use Browser Solidity on your local machine to connect to your local machine port which is a proxy for your remote server's geth
RPC port - see How can I expose Geth's RPC server to external connections?
Set up your local machine's geth
instance to be a peer to your remote server's geth
instance. You can then use Browser Solidity to interact with your local machine's geth
instance and your actions will be mirrored on your remote server. See Losing connection between nodes on private network and search for private network on this site.
Update With Source Code Provided In Comments Below
Here is the source code from the link below, unaltered except for the pragma
statement and the addition of constant
to the test_callstack()
function:
library LinkedList {
uint80 constant None = uint80(0); // NULL.
struct data {
uint256 head;
Node[100] n;
uint size;
uint insert_number;
uint buffer_size;
}
struct Node {
string data;
address owner;
uint own;
uint prev;
uint next;
}
function construct_me(data storage self){
self.n[0].own = 0;
self.n[0].next = 0;
self.n[0].prev = 0;
self.head = 0;
self.insert_number = self.size = 1;
self.buffer_size = 100;
}
}
contract owned {
address public owner;
function owned() {
owner = msg.sender;
}
function ownerOnly() {
if (msg.sender != owner) throw;
}
modifier onlyOwner {
if (msg.sender != owner) throw;
_;
}
function transferOwnership(address newOwner) onlyOwner {
owner = newOwner;
}
}
contract Array is owned {
using LinkedList for LinkedList.data;
using LinkedList for LinkedList.Node;
LinkedList.data list;
function Array(){
if( test_callstack() != 1 ) throw;
list.construct_me();
}
function test_callstack() constant returns ( int ){ return 1; }
}
I've saved the source code above into Contract.sol
.
I use the following statement to assign the flattened source code to a variable (reference https://ethereum.stackexchange.com/a/2610/1268):
Iota:DeployLibrary user$ echo "var myContractSource='`$HOME/bin/stripCrLf Contract.sol`'"
var myContractSource="library LinkedList { uint80 constant None = uint80(0); struct data { uint256 head; Node[100] n; uint size; uint insert_number; uint buffer_size; } struct Node { string data; address owner; uint own; uint prev; uint next; } function construct_me(data storage self){ self.n[0].own = 0; self.n[0].next = 0; self.n[0].prev = 0; self.head = 0; self.insert_number = self.size = 1; self.buffer_size = 100; }}contract owned { address public owner; function owned() { owner = msg.sender; } function ownerOnly() { if (msg.sender != owner) throw; } modifier onlyOwner { if (msg.sender != owner) throw; _; } function transferOwnership(address newOwner) onlyOwner { owner = newOwner; }}contract Array is owned { using LinkedList for LinkedList.data; using LinkedList for LinkedList.Node; LinkedList.data list; function Array(){ if( test_callstack() != 1 ) throw; list.construct_me(); } function test_callstack() constant returns ( int ){ return 1; }}"
I copied the line above into my clipboard and pasted it into a --dev
geth instance:
> var myContractSource="library LinkedList { uint80 constant None = uint80(0); struct data { uint256 head; Node[100] n; uint size; uint insert_number; uint buffer_size; } struct Node { string data; address owner; uint own; uint prev; uint next; } function construct_me(data storage self){ self.n[0].own = 0; self.n[0].next = 0; self.n[0].prev = 0; self.head = 0; self.insert_number = self.size = 1; self.buffer_size = 100; }}contract owned { address public owner; function owned() { owner = msg.sender; } function ownerOnly() { if (msg.sender != owner) throw; } modifier onlyOwner { if (msg.sender != owner) throw; _; } function transferOwnership(address newOwner) onlyOwner { owner = newOwner; }}contract Array is owned { using LinkedList for LinkedList.data; using LinkedList for LinkedList.Node; LinkedList.data list; function Array(){ if( test_callstack() != 1 ) throw; list.construct_me(); } function test_callstack() constant returns ( int ){ return 1; }}"
undefined
I compiled the source code:
> var myContractCompiled=web3.eth.compile.solidity(myContractSource);
undefined
To check the available ABIs, I type the following:
> myContractCompiled
myContractCompiled
{
Array: {
code: "0x6060604081905260008054600160a060020a0319166c01000000000000000000000000338102041781557f14ea1cf8000000000000000000000000000000000000000000000000000000008252600160645273__LinkedList____________________________916314ea1cf89160849160248186803b1560025760325a03f41560025750505060fd806100936000396000f3606060405260e060020a60003504631309238c8114603a578063896f40dd1460525780638da5cb5b146071578063f2fde38b146086575b6002565b34600257600160408051918252519081900360200190f35b3460025760a860005433600160a060020a0390811691161460c6576002565b3460025760aa600054600160a060020a031681565b3460025760a860043560005433600160a060020a0390811691161460c8576002565b005b60408051600160a060020a039092168252519081900360200190f35b565b600080546c010000000000000000000000008084020473ffffffffffffffffffffffffffffffffffffffff199091161790555056",
info: {
abiDefinition: [{...}, {...}, {...}, {...}, {...}],
compilerOptions: "--combined-json bin,abi,userdoc,devdoc --add-std --optimize",
compilerVersion: "0.4.4",
developerDoc: {
methods: {}
},
language: "Solidity",
languageVersion: "0.4.4",
source: "library LinkedList { uint80 constant None = uint80(0); struct data { uint256 head; Node[100] n; uint size; uint insert_number; uint buffer_size; } struct Node { string data; address owner; uint own; uint prev; uint next; } function construct_me(data storage self){ self.n[0].own = 0; self.n[0].next = 0; self.n[0].prev = 0; self.head = 0; self.insert_number = self.size = 1; self.buffer_size = 100; }}contract owned { address public owner; function owned() { owner = msg.sender; } function ownerOnly() { if (msg.sender != owner) throw; } modifier onlyOwner { if (msg.sender != owner) throw; _; } function transferOwnership(address newOwner) onlyOwner { owner = newOwner; }}contract Array is owned { using LinkedList for LinkedList.data; using LinkedList for LinkedList.Node; LinkedList.data list; function Array(){ if( test_callstack() != 1 ) throw; list.construct_me(); } function test_callstack() constant returns ( int ){ return 1; }}",
userDoc: {
methods: {}
}
}
},
LinkedList: {
code: "0x6060604052605c8060106000396000f36504044633f3de50606060405260e060020a600035046314ea1cf881146024575b6007565b600060036004803591820183905560058201839055810182905590815560016101f582018190556101f682015560646101f79091015500",
info: {
abiDefinition: [{...}],
compilerOptions: "--combined-json bin,abi,userdoc,devdoc --add-std --optimize",
compilerVersion: "0.4.4",
developerDoc: {
methods: {}
},
language: "Solidity",
languageVersion: "0.4.4",
source: "library LinkedList { uint80 constant None = uint80(0); struct data { uint256 head; Node[100] n; uint size; uint insert_number; uint buffer_size; } struct Node { string data; address owner; uint own; uint prev; uint next; } function construct_me(data storage self){ self.n[0].own = 0; self.n[0].next = 0; self.n[0].prev = 0; self.head = 0; self.insert_number = self.size = 1; self.buffer_size = 100; }}contract owned { address public owner; function owned() { owner = msg.sender; } function ownerOnly() { if (msg.sender != owner) throw; } modifier onlyOwner { if (msg.sender != owner) throw; _; } function transferOwnership(address newOwner) onlyOwner { owner = newOwner; }}contract Array is owned { using LinkedList for LinkedList.data; using LinkedList for LinkedList.Node; LinkedList.data list; function Array(){ if( test_callstack() != 1 ) throw; list.construct_me(); } function test_callstack() constant returns ( int ){ return 1; }}",
userDoc: {
methods: {}
}
}
},
owned: {
code: "0x6060604052600080546c0100000000000000000000000033810204600160a060020a031990911617905560db806100366000396000f3606060405260e060020a6000350463896f40dd811460305780638da5cb5b14604f578063f2fde38b146064575b6002565b34600257608660005433600160a060020a0390811691161460a4576002565b346002576088600054600160a060020a031681565b34600257608660043560005433600160a060020a0390811691161460a6576002565b005b60408051600160a060020a039092168252519081900360200190f35b565b600080546c010000000000000000000000008084020473ffffffffffffffffffffffffffffffffffffffff199091161790555056",
info: {
abiDefinition: [{...}, {...}, {...}, {...}],
compilerOptions: "--combined-json bin,abi,userdoc,devdoc --add-std --optimize",
compilerVersion: "0.4.4",
developerDoc: {
methods: {}
},
language: "Solidity",
languageVersion: "0.4.4",
source: "library LinkedList { uint80 constant None = uint80(0); struct data { uint256 head; Node[100] n; uint size; uint insert_number; uint buffer_size; } struct Node { string data; address owner; uint own; uint prev; uint next; } function construct_me(data storage self){ self.n[0].own = 0; self.n[0].next = 0; self.n[0].prev = 0; self.head = 0; self.insert_number = self.size = 1; self.buffer_size = 100; }}contract owned { address public owner; function owned() { owner = msg.sender; } function ownerOnly() { if (msg.sender != owner) throw; } modifier onlyOwner { if (msg.sender != owner) throw; _; } function transferOwnership(address newOwner) onlyOwner { owner = newOwner; }}contract Array is owned { using LinkedList for LinkedList.data; using LinkedList for LinkedList.Node; LinkedList.data list; function Array(){ if( test_callstack() != 1 ) throw; list.construct_me(); } function test_callstack() constant returns ( int ){ return 1; }}",
userDoc: {
methods: {}
}
}
}
}
Note that myContractCompiled.Array.code
contains the text __LinkedList__...___
. This will need to be replaced with the address (without the 0x
prefix) of the deployed LinkedList
library.
Deploy the LinkedList
library:
> var myLinkedListLib = web3.eth.contract(myContractCompiled.LinkedList.info.abiDefinition);
undefined
> var linkedListLib = myLinkedListLib.new({
from:web3.eth.accounts[0],
data: myContractCompiled.LinkedList.code, gas: 400000},
function(e, contract) {
if (!e) {
if (!contract.address) {
console.log("Contract transaction send: TransactionHash: " +
contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
})
Contract transaction send: TransactionHash: 0x420908d8f22649542d532f256dff3ae5a7b473c68c68274d8c83ba9539f6d0e1 waiting to be mined...
Contract mined! Address: 0xc6fa3b899c8840585e706f90d1e43c7229cf9d5d
Let's check the gas used:
> eth.getTransactionReceipt("0x420908d8f22649542d532f256dff3ae5a7b473c68c68274d8c83ba9539f6d0e1")
{
blockHash: "0xff0ba9946211a9d3b0824e5758d148334ef1de6689c8fba70916e52bd35e2167",
blockNumber: 2370,
contractAddress: "0xc6fa3b899c8840585e706f90d1e43c7229cf9d5d",
cumulativeGasUsed: 78469,
from: "0x000d1009bd8f0b1301cc5edc28ed1222a3ce671e",
gasUsed: 78469,
logs: [],
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
root: "0x9c7f63caedfd133826622a2872907fc52ede05cc9c0b644bfadf92bcfa5aaed5",
to: null,
transactionHash: "0x420908d8f22649542d532f256dff3ae5a7b473c68c68274d8c83ba9539f6d0e1",
transactionIndex: 0
}
Replace the __LinkedList__*
text with the above address in the Array contract code.
> var arrayCode = myContractCompiled.Array.code.replace(/__LinkedList__+/g, "c6fa3b899c8840585e706f90d1e43c7229cf9d5d")
undefined
> arrayCode
"0x6060604081905260008054600160a060020a0319166c01000000000000000000000000338102041781557f14ea1cf8000000000000000000000000000000000000000000000000000000008252600160645273c6fa3b899c8840585e706f90d1e43c7229cf9d5d916314ea1cf89160849160248186803b1560025760325a03f41560025750505060fd806100936000396000f3606060405260e060020a60003504631309238c8114603a578063896f40dd1460525780638da5cb5b146071578063f2fde38b146086575b6002565b34600257600160408051918252519081900360200190f35b3460025760a860005433600160a060020a0390811691161460c6576002565b3460025760aa600054600160a060020a031681565b3460025760a860043560005433600160a060020a0390811691161460c8576002565b005b60408051600160a060020a039092168252519081900360200190f35b565b600080546c010000000000000000000000008084020473ffffffffffffffffffffffffffffffffffffffff199091161790555056"
Deploy Array
with the modified code:
> var myArray = web3.eth.contract(myContractCompiled.Array.info.abiDefinition);
undefined
> var array = myArray.new({
from:web3.eth.accounts[0],
data: arrayCode, gas: 400000},
function(e, contract) {
if (!e) {
if (!contract.address) {
console.log("Contract transaction send: TransactionHash: " +
contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
})
Contract transaction send: TransactionHash: 0x2652d322915ec6f3668a701b5ef41c09cf5aa93de0fd7c18f8de9250a9811505 waiting to be mined...
undefined
...
Contract mined! Address: 0x036a55eb6419b503692eeedd3c446f9252642001
I0103 19:47:37.967249 miner/worker.go:516] commit new work on block 1504 with 1 txs & 0 uncles. Took 4.177908ms
...
> eth.getTransactionReceipt("0x2652d322915ec6f3668a701b5ef41c09cf5aa93de0fd7c18f8de9250a9811505")
{
blockHash: "0xb6da4bcb8349333f023ed9fc41c47275e27bd1cc446c130842ee8eda51323ee9",
blockNumber: 2429,
contractAddress: "0x036a55eb6419b503692eeedd3c446f9252642001",
cumulativeGasUsed: 227373,
from: "0x000d1009bd8f0b1301cc5edc28ed1222a3ce671e",
gasUsed: 227373,
logs: [],
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
root: "0x4fe08613be0eb3475f25cec740b723d8124161bc36093cf2064543ef3e6cdd45",
to: null,
transactionHash: "0x2652d322915ec6f3668a701b5ef41c09cf5aa93de0fd7c18f8de9250a9811505",
transactionIndex: 0
}
Let's test your function:
> array.test_callstack()
1
Note: The code above requires the homesteadBlock
configuration to be specified in your genesis.json
if you are deploying your library calling contract to a private/dev network - see How to call Library Function from a Contract? => [error] The contract code couldn't be stored, please check your gas amount. undefined.