remix-project mirror
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
remix-project/docs/tutorial_geth-remix.md

280 lines
8.9 KiB

Debugging a Dapp using Remix & Geth
==========================================
The ultimate goal of this tutorial is to debug transactions that have
been created by a dapp front end.
It is easy in Remix to debug a transaction created from its own GUI.
However, setting up an environment that allows you to debug transactions
created outside of Remix, require a bit more of complexity.
We will need four tools for that :
> - Geth - this is the center piece and provides the blockchain
> environment. We will basically run geth in a dev mode.
> - Remix - this is the Ethereum IDE. We will use it to develop our
> Solidity contract.
> - Any code editor you want - in order to write your front end :)
Install the environment
-----------------------
### Install Metamask
Basically we will run our front end in the Metamask Chrome plugin ([Metamask](http://metamask.io)).
### Install Geth
[Geth](http://github.com/ethereum/go-ethereum/releases) is the official
Ethereum client.
Running the environment
-----------------------
### Run Geth
We will run a test node. This node will have a new empty state and will
not be synced to the main or ropsten network.
geth --ipcpath <test-chain-directory>/geth.ipc --datadir <test-chain-directory> --dev console
`<test-chain-directory>` is the folder where keys and chain data will be
stored.
`--ipcpath` defines the end point that other apps (like Metamask) use to
talk to geth.
`--datadir` specifies the data directory.
`--dev` sets the node into private chain mode and adds some debugging
flags.
Then we need to create accounts and mine a bit to generate some Ether:
// from the geth console :
personal.newAccount() // You can execute this command several time if you need more than one account.
miner.start() // generate some Ether.
miner.stop() // stop mining after 30s-60s - we could also keep mining.
Next time we run Geth, we will only need to mine transactions (no need
to recreate account).
### Starting Remix
In Mist click on `Develop` / `Open Remix IDE`
Remix will open in a new window. If this is the first time it is run,
the `Ballot` contract will be loaded.
Now, we need to check if Remix is connected to Mist:
Right panel / third tab from the left, `Injected Provider` should be
checked.
![image](remix4.png)
Right panel / second tab from the left, `Transaction Origin` should
contain accounts we have previously created in Geth.
![image](remix5.png)
Developing contract / front end
-------------------------------
### Donation contract - Dapp Back end
Here is a sample solidity contract.
Copy and paste the following inside remix:
```
{.sourceCode .none}
contract Donation {
address owner;
event fundMoved(address _to, uint _amount);
modifier onlyowner { if (msg.sender == owner) _; }
address[] _giver;
uint[] _values;
function Donation() {
owner = msg.sender;
}
function donate() payable {
addGiver(msg.value);
}
function moveFund(address _to, uint _amount) onlyowner {
uint balance = this.balance;
uint amount = _amount;
if (_amount <= this.balance) {
if (_to.send(this.balance)) {
fundMoved(_to, _amount);
} else {
throw;
}
} else {
throw;
}
}
function addGiver(uint _amount) internal {
_giver.push(msg.sender);
_values.push(_amount);
}
}
```
### Dapp Front end
and here is the front end:
```html
<div>
<div>Donation Contract</div>
<br/>
<input id='contractaddress' placeholder='contract address' />
<br/>
<div>
<br/>
<input id='fromGive' placeholder='from' /><input placeholder='amount' id='valueGive' /><button id="fallbackbtn" onclick="donate()">give</button>
<br/>
<br/>
<input id='fromMoveFund' placeholder='from' /><input id='moveFundTo' placeholder='move to' /><input id='amountToMove' placeholder='amount' /><button id="movefundbtn" onclick="movefund()">moveFund</button>
<br/>
<br/>
<div id='wait' ></div>
</div>
<br/>
<br/>
<div id='log'>
</div>
</div>
<script type="text/javascript">
function donate () {
var donation = contractspec.at(document.getElementById('contractaddress').value)
donation.donate({
from: document.getElementById('fromGive').value,
value: document.getElementById('valueGive').value
}, function (error, txHash) {
tryTillResponse(txHash, function (error, receipt) {
alert('done ' + txHash)
})
})
}
function movefund () {
var donation = contractspec.at(document.getElementById('contractaddress').value)
donation.moveFund(
document.getElementById('moveFundTo').value,
document.getElementById('amountToMove').value,
function (error, txHash) {
tryTillResponse(txHash, function (error, receipt) {
alert('done ' + txHash)
})
})
}
var contractspec = web3.eth.contract([{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"moveFund","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"donate","outputs":[],"payable":true,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"fundMoved","type":"event"}]);
function tryTillResponse (txhash, done) {
document.getElementById('wait').innerHTML = 'waiting for the transaction to be mined ...'
web3.eth.getTransactionReceipt(txhash, function (err, result) {
if (!err && !result) {
// Try again with a bit of delay
setTimeout(function () { tryTillResponse(txhash, done) }, 500)
} else {
document.getElementById('wait').innerHTML = ''
var log = document.createElement("div")
log.innerHTML = JSON.stringify(result)
document.getElementById('log').appendChild(log)
done(err,result)
}
})
}
</script>
```
I would suggest serving this file using `http-serve`, but you can use
any web server you like.
Example: Dapp Front End <https://github.com/ltfschoen/dapp_front_end>
### Important notice !
The variable `contractspec` contains the abi of the `donation` contract.
This means that if you change something in the contract interface
(function names, parameters, ...) you need to copy the new abi from
remix to the front end.
Deploying
---------
Right panel / Red button `Create`
![image](remix1.png)
This creates a new transaction that deploys the `Donation` contract
(Mist will ask for the usual passphrase check).
Wait for the transaction to be mined (don't forget to activate mining
`miner.start()`). Once this is done, you can use it by executing the
`moveFund` and `donate` function. But this is not what we want to
achieve. We want to run and debug those functions from the front end.
Remix also display the address of the contract. Save it, we'll need this
address later.
![image](remix2.png)
Debugging
---------
From Mist, browse the above front end. In the first field, paste the
address of the newly created contract. Now, let's call the first
function (label `give`).
You will need an account and a value.
The account could be any account that is declared in the Wallet section
of Mist. This is the sender of the transaction that we are going to
create. The value should be no more than the actual balance of the
account - the unit is in wei, so just put `100` (100 wei), that should
be fine.
Click on `Give` and wait for the transaction to be mined.
The HTML block with id `log` is filled by all the transactions created
from the front end. It was easier for the purpose of this tutorial to
just log transactions in a div but you can have your own logging
mechanism.
There is only one field that we need, this is the `transactionHash`.
Copy it and switch to Remix. On the right side, the fifth panel shows a
small "bug" icon, that is the debugger.
Paste the hash into the transaction field and click on the `play`
button.
![image](remix3.png)
You are now entering a debug session for the call to `donate`.
Debugging in Remix is easier than with common tools like gdb because you
can freely move in time. Use the slider to change the current step and
click on the panels below to expand them and explore the curret state,
local variables, etc. There are also breakpoints to move between
sections of the code quickly, but more on all that later.
At the time of this writing, there is an issue that could break the
contract creation. The a workaround for that at
<https://github.com/ethereum/go-ethereum/issues/3653> . Please follow
the workaround or wait for this issue to be closed.
Also, although retrieving a contract's storage when Remix is using the
JavaScript VM is working well, there is still work to be done when Remix
is using eth or geth as backend.