Here's your function slightly modified by adding public
to numbers
so we can peek at the data:
contract C {
uint[] public numbers;
function initNumbers() {
numbers.push(1);
numbers.push(2);
}
function stateChanger(uint a) {
numbers.push(a);
}
}
Using the stripCrLf
script in How to load Solidity source file into geth, I've flattened the source code using the following command:
user@Kumquat:~$ echo "var cSource='`stripCrLf C.sol`'"
var cSource='contract C { uint[] public numbers; function initNumbers() { numbers.push(1); numbers.push(2); } function stateChanger(uint a) { numbers.push(a); } }'
I'm running a dev network using the following command (I have my password in passwordfile
):
user@Kumquat:~$ geth --datadir ~/devdata --dev --mine --minerthreads 1 --unlock 0 --password ~/passwordfile console
I paste the flattened code in the geth
command line:
> var cSource='contract C { uint[] public numbers; function initNumbers() { numbers.push(1); numbers.push(2); } function stateChanger(uint a) { numbers.push(a); } }'
undefined
And compile the code using the following command:
> var cCompiled = web3.eth.compile.solidity(cSource);
Version: 0.3.5-0/RelWithDebInfo-Linux/g++/Interpreter
path: /usr/bin/solc
undefined
Here is the Application Binary Interface:
> cCompiled.C.info.abiDefinition
[{
constant: false,
inputs: [],
name: "initNumbers",
outputs: [],
type: "function"
}, {
constant: false,
inputs: [{
name: "a",
type: "uint256"
}],
name: "stateChanger",
outputs: [],
type: "function"
}, {
constant: true,
inputs: [{
name: "",
type: "uint256"
}],
name: "numbers",
outputs: [{
name: "",
type: "uint256"
}],
type: "function"
}]
Deploy the contract on the blockchain:
> var cContract = web3.eth.contract(cCompiled.C.info.abiDefinition);
undefined
> var c = cContract.new({
from:web3.eth.accounts[0],
data: cCompiled.C.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 mined! Address: 0x672807a8c0f72a52d759942e86cfe33264e73934
Call your initNumbers()
:
> c.initNumbers({from:eth.accounts[0], gas: 400000})
"0x3f21e1cdb636a2cf291cd9296282a4e9c4f4ed57c65a13fedc937a97203c3a75"
...
> c.numbers(0)
1
> c.numbers(1)
2
> c.numbers(2)
0
Calling stateChanger(...)
- Method 1
> c.stateChanger(3, {from:eth.accounts[0], gas: 400000})
"0x3ecf3aa6464f93d5b062ad01b76b5dbc4302c190baf70d157a4d7607d4c7c749"
...
> c.numbers(2)
3
> c.numbers(3)
0
Calling stateChanger(...)
- Method 2
> c.stateChanger.sendTransaction(4, {from: eth.accounts[0], gas: 400000})
"0xe1d9c57ca55dbdf446e55602570888ff5efce97a91ddc5c9575d10c7c9a1f0c8"
...
> c.numbers(3)
4
> c.numbers(4)
0
Calling stateChanger(...)
- Method 3
And following is how to use the raw data sendTransaction(...)
format.
Find the function signature. Note that the uint
parameter is actually a uint256
(see the ABI format above):
> web3.sha3('stateChanger(uint256)').substr(0, 10)
"0x65060775"
Here is 5 encoded in hex and padded to 32 bytes:
0x0000000000000000000000000000000000000000000000000000000000000005
Join the data together, removing the 0x
from the hex(5) string:
0x650607750000000000000000000000000000000000000000000000000000000000000005
Here's how to sendTransaction(...)
. The to:
parameter is the address of the mined contract:
> var result = web3.eth.sendTransaction({
from: eth.accounts[0],
to: "0x672807a8c0f72a52d759942e86cfe33264e73934",
data: "0x650607750000000000000000000000000000000000000000000000000000000000000005",
gas: 400000}
)
undefined
> result
"0x420d4256718b4326967677da2e460a1d361a62f3ceee386e1313d25b12c0f610"
...
> c.numbers(4)
5
> c.numbers(5)
0
Bonus 1 - estimateGas(...)
Since we have worked out the data to send with sendTransaction(...)
above.
Here is the gas used by the sendTransaction(...)
call above:
> eth.getTransactionReceipt(result).gasUsed
46888
You can use the same data format to estimate the gas using the estimateGas(...)
call:
var result = web3.eth.estimateGas({
from: eth.accounts[0],
to: "0x672807a8c0f72a52d759942e86cfe33264e73934",
data: "0x650607750000000000000000000000000000000000000000000000000000000000000005",
gas: 400000}
)
undefined
> result
46888
Bonus 2 - The Transaction Data
Set debug.verbosity(7)
and watch the transaction get removed from the transaction pool after it is executed:
> debug.verbosity(7)
...
I0730 00:13:43.918828 core/tx_pool.go:547] removed tx (
TX(07c3c717c87ce1e2b31ba144b6b751d66c90a8a69375478a5ef4e60a6f42996c)
Contract: false
From: a7857047907d53a2e494d5f311b4b586dc6a96d2
To: 672807a8c0f72a52d759942e86cfe33264e73934
Nonce: 35
GasPrice: 20000000000
GasLimit 400000
Value: 0
Data: 0x650607750000000000000000000000000000000000000000000000000000000000000004
V: 0x1c
R: 0x75ff67a969670a0f35ae415f2fa541446a71fa9b7d8ad6247ad12fd7ae3986a
S: 0x7150424ed1698792cdcf1253a79f2474e4df411610db97e36240bab50af6c80c
Hex: f889238504a817c80083061a8094672807a8c0f72a52d759942e86cfe33264e7393480a46506077500000000000000000000000000000000000000000000000000000000000000041ca0075ff67a969670a0f35ae415f2fa541446a71fa9b7d8ad6247ad12fd7ae3986aa07150424ed1698792cdcf1253a79f2474e4df411610db97e36240bab50af6c80c
) from pool: low tx nonce or out of funds
The different methods of calling (c.stateChanger(3, {from:eth.accounts[0], gas: 400000})
and c.stateChanger.sendTransaction(4, {from: eth.accounts[0], gas: 400000})
) are converted to the sendTransaction(...)
format.
Yes.
The calling contract needs two things; the address of the contract to be called, and a description of the ABI. The ABI is, in summary, a description of the function names and layout of the arguments.
You often see the contracts in the same file because it gives the compiler the information it needs about the ABI. In many cases, one or more of the contracts won't be deployed manually, but rather through a process in one or more other contracts.
You might see something like this:
import "/Utility.sol"; // something already deployed. We want the code so the compiler can see the interface.
contract Factory { // something that deploys instances
Utility utility; // Type is Utility (contract)
function Factory(address _utility) {
utility = Utility(_utility); // Utility at the supplied (known) address
}
function newInstance() returns(address contract) {
Instance = new Instance(utility); // make a new instance and inform about another contract's address
return instance;
}
contract Instance { // something that will copied/deployed many times
Utility utility;
function Instance(address _utility) { // utility address passed in
utility = Utility(_utility); // get set to use the Utility
}
}
In the above, the idea is that Utility is deployed, and the deployer knows the address, so they pass it into the contructor when they deploy the Factory (otherwise, how will it know?). They don't need to deploy an Instance because the Factory does that. The compiler still needs to see all three source files when Factory gets compiled. Factory needs a copy of the bytecode it's supposed to deploy with new Instance();
and it needs the interface to Utility because the other two contracts both talk to it.
A little more practical example over here: Is There a Simple Contract Factory Pattern?
Hope it helps.
Best Answer
In this context it doesn't make much difference when the exception is raised. Transactions are atomic: either they succeed fully or they are fully reverted back.
So if there is a revert anywhere in the execution path, the whole transaction is reverted back, and all changes made by it are reverted. (This is not 100% correct: external contracts' revertions can be for example caught by try-catch blocks.)
So you don't really need to worry about some residual state changes.