parent
98679ed2a0
commit
2e7bc0f4ae
|
@ -0,0 +1,143 @@
|
||||||
|
---
|
||||||
|
title: JavaScript Console 2 - Contracts
|
||||||
|
sort_key: D
|
||||||
|
---
|
||||||
|
|
||||||
|
The [Introduction to the Javascript console](src/pages/docs/interacting-with-geth/javascript-console.md)
|
||||||
|
page outlined how a Javascript console can be attached to Geth to provide a more
|
||||||
|
user-friendly interface to Ethereum than interacting directly with the JSON-RPC API.
|
||||||
|
This page will describe how to deploy contracts and interact with contracts using
|
||||||
|
the attached console. This page will assume the Javascript console is attached to
|
||||||
|
a running Geth instance using IPC. Clef should be used to manage accounts.
|
||||||
|
|
||||||
|
## Deploying a contract
|
||||||
|
|
||||||
|
First we need a contract to deploy. We can use the well-known `Storage.sol` contract
|
||||||
|
written in Solidity. The following Solidity code can be copied and pasted into a text
|
||||||
|
editor and saved as `go-ethereum/storage-contract/Storage.sol`.
|
||||||
|
|
||||||
|
```Solidity
|
||||||
|
// SPDX License-Identifier: GPL 3.0
|
||||||
|
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract Storage{
|
||||||
|
|
||||||
|
uint256 value = 5;
|
||||||
|
|
||||||
|
function set(uint256 number) public{
|
||||||
|
value = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function retrieve() public view returns (uint256){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The contract needs to be compiled before Geth can understand it. Compiling the
|
||||||
|
contract creates an [Application Binary Interface](https://docs.soliditylang.org/en/v0.4.24/abi-spec.html)
|
||||||
|
and the contract bytecode. This requires a Solidity compiler (e.g. `solc`) to be
|
||||||
|
installed on the local machine. Then, compile and save the ABI and bytecode to a
|
||||||
|
new `build` subdirectory using the following terminal commands:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd ~/go-ethereum/storage-contract
|
||||||
|
solc --bin Storage.sol -o build
|
||||||
|
solc --abi Storage.sol -o build
|
||||||
|
```
|
||||||
|
|
||||||
|
The outputs look as follows:
|
||||||
|
|
||||||
|
Storage.bin:
|
||||||
|
```sh
|
||||||
|
608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea264697066735822122031443f2fb748bdb27e539fdbeb0c6f575aec50508baaa7e4dbeb08577ef19b3764736f6c63430008110033
|
||||||
|
```
|
||||||
|
|
||||||
|
Storage.abi:
|
||||||
|
```json
|
||||||
|
[{"inputs":[],"name":"retrieve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}]
|
||||||
|
```
|
||||||
|
|
||||||
|
These are all the data required to deploy the contract using the Geth Javascript
|
||||||
|
console. Open the Javascript console using `./geth attach geth.ipc`.
|
||||||
|
|
||||||
|
Now, for convenice we can store the abi and bytecode in variables in the console:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var abi = [{"inputs":[],"name":"retrieve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}]
|
||||||
|
|
||||||
|
var bytecode = "608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea264697066735822122031443f2fb748bdb27e539fdbeb0c6f575aec50508baaa7e4dbeb08577ef19b3764736f6c63430008110033"
|
||||||
|
```
|
||||||
|
|
||||||
|
The ABI can be used to create an instance of the contract:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var contract = eth.contract(abi)
|
||||||
|
```
|
||||||
|
|
||||||
|
This contract instance can then be deployed to the blockchain. This is done
|
||||||
|
using `eth.sendTransaction`, passing the contract bytecode in the `data` field.
|
||||||
|
For convenience we can create a transaction JSON object first, then pass it to
|
||||||
|
`eth.sendTransaction` later. Let's use the first account in `eth.accounts` as the
|
||||||
|
sender. The amount of gas to include can be determined using `eth.estimateGas`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var gas = eth.estimateGas({data: bytecode})
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note that each command that touches accounts will require approval in Clef unless
|
||||||
|
a custom rule has been implemented.**
|
||||||
|
|
||||||
|
The bytecode, gas and address of the sender can be bundled together into an object
|
||||||
|
that will be passed to the contract's `new()` method which deploys the contract.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var tx = {'from': eth.accounts[0], data: bytecode, gas: gas}
|
||||||
|
var deployed_contract = contract.new(tx)
|
||||||
|
```
|
||||||
|
|
||||||
|
The transaction hash and deployment address can now been viewed in the console by
|
||||||
|
entering the variable name (in this case `deployed_contract`):
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
abi:[{
|
||||||
|
inputs: [],
|
||||||
|
name: "retrieve",
|
||||||
|
outputs: [{...}],
|
||||||
|
stateMutability: "view",
|
||||||
|
type: "function"
|
||||||
|
},{
|
||||||
|
inputs: [],
|
||||||
|
name: "store",
|
||||||
|
outputs: [{...}],
|
||||||
|
stateMutability: "nonpayable",
|
||||||
|
type: "function"
|
||||||
|
}],
|
||||||
|
address: "0x2d6505f8b1130a22a5998cd31788bf6c751247f",
|
||||||
|
transactionHash: "0x5040a8916b23b76696ea9eba5b072546e1112cc481995219081fc86f5b911bf3",
|
||||||
|
allEvents: function bound(),
|
||||||
|
retrieve: function bound(),
|
||||||
|
store: function bound()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Passing the transaction hash to `eth.getTransaction()` returns more detailed deployment
|
||||||
|
transaction details. To interact with the contract, create an instance by passing the
|
||||||
|
deployment address to `contract.at()` then call the methods.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var instance = contract.at("0x2d6505f8b1130a22a5998cd31788bf6c751247f")
|
||||||
|
// store() alters the state and therefore requires sendTransaction()
|
||||||
|
contract.set.sendTransaction(42, {from: eth.accounts[0], gas: 1000000})
|
||||||
|
// retrieve does not alter state so it can be executed using call()
|
||||||
|
contract.retrieve().call()
|
||||||
|
|
||||||
|
>> 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
This page demonstrated how to create, compile, deploy and interact with an Ethereum
|
||||||
|
smart contract using Geth's Javascript console.
|
|
@ -3,7 +3,7 @@ title: JavaScript Console
|
||||||
sort_key: D
|
sort_key: D
|
||||||
---
|
---
|
||||||
|
|
||||||
Geth responds to instructions encoded as JSON objects as defined in the [JSON-RPC-API](/docs/rpc/server). A Geth user can send these instructions directly, for example over HTTP using tools like [Curl](https://github.com/curl/curl). The code snippet below shows a request for an account balance sent to a local Geth node with the HTTP port `8545` exposed.
|
Geth responds to instructions encoded as JSON objects as defined in the [JSON-RPC-API](/docs/rpc/server). The code snippet below shows a request for an account balance sent to a local Geth node using curl.
|
||||||
|
|
||||||
```
|
```
|
||||||
curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0x9b1d35635cc34752ca54713bb99d38614f63c955", "latest"], "id":2}' -H "Content-Type: application/json" localhost:8545
|
curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0x9b1d35635cc34752ca54713bb99d38614f63c955", "latest"], "id":2}' -H "Content-Type: application/json" localhost:8545
|
||||||
|
@ -15,7 +15,7 @@ This returns a result which is also a JSON object, with values expressed as hexa
|
||||||
{"id":2,"jsonrpc":"2.0","result":"0x1639e49bba16280000"}
|
{"id":2,"jsonrpc":"2.0","result":"0x1639e49bba16280000"}
|
||||||
```
|
```
|
||||||
|
|
||||||
While this approach is valid, it is also a very low level and rather error-prone way to interact with Geth. Most developers prefer to use convenience libraries that abstract away some of the more tedious and awkward tasks such as converting values from hexadecimal strings into numbers, or converting between denominations of ether (Wei, Gwei, etc). One such library is [Web3.js](https://web3js.readthedocs.io/en/v1.7.3/). This is a collection of Javascript libraries for interacting with an Ethereum node at a higher level than sending raw JSON objects to the node. The purpose of Geth's Javascript console is to provide a built-in environment to use a subset of the Web3.js libraries to interact with a Geth node.
|
This is a low level and rather error-prone way to interact with Geth. Most developers prefer to use convenience libraries that abstract away some of the more tedious and awkward tasks such as converting values from hexadecimal strings into numbers, or converting between denominations of ether (Wei, Gwei, etc). One such library is [Web3.js](https://web3js.readthedocs.io/en/v1.7.3/). The purpose of Geth's Javascript console is to provide a built-in environment to use a subset of the Web3.js libraries to interact with a Geth node.
|
||||||
|
|
||||||
{% include note.html content="The web3.js version that comes bundled with Geth is not up to date with the official Web3.js documentation. There are several Web3.js libraries that are not available in the Geth Javascript Console. There are also administrative APIs included in the Geth console that are not documented in the Web3.js documentation. The full list of libraries available in the Geth console is available on the [JSON-RPC API page](/docs/rpc/server)." %}
|
{% include note.html content="The web3.js version that comes bundled with Geth is not up to date with the official Web3.js documentation. There are several Web3.js libraries that are not available in the Geth Javascript Console. There are also administrative APIs included in the Geth console that are not documented in the Web3.js documentation. The full list of libraries available in the Geth console is available on the [JSON-RPC API page](/docs/rpc/server)." %}
|
||||||
|
|
||||||
|
@ -39,7 +39,6 @@ Alternatively, a Javascript console can be attached to an existing Geth instance
|
||||||
geth <other flags> --ws
|
geth <other flags> --ws
|
||||||
|
|
||||||
# enable http
|
# enable http
|
||||||
|
|
||||||
geth <other flags> --http
|
geth <other flags> --http
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -53,9 +52,9 @@ geth <other commands> --http --http.addr 192.60.52.21 --http.port 8552 --http.ap
|
||||||
geth <other commands> --ws --ws.addr 192.60.52.21 --ws.port 8552 --ws.api eth,web3,admin
|
geth <other commands> --ws --ws.addr 192.60.52.21 --ws.port 8552 --ws.api eth,web3,admin
|
||||||
```
|
```
|
||||||
|
|
||||||
It is important to note that by default **some functionality, including account unlocking is forbidden when HTTP or Websockets access is enabled**. This is because an attacker that manages to access the node via the externally-exposed HTTP/WS port then control the unlocked account. It is possible to force account unlock by including the `--allow-insecure-unlock` flag but this is not recommended if there is any chance of the node connecting to Ethereum Mainnet. This is not a hypothetical risk: **there are bots that continually scan for http-enabled Ethereum nodes to attack**"
|
It is important to note that by default **some functionality, including account unlocking is forbidden when HTTP or Websockets access is enabled**. This is because an attacker that manages to access the node via the externally-exposed HTTP/WS port then control the unlocked account. This is not a hypothetical risk: **there are bots that continually scan for http-enabled Ethereum nodes to attack**"
|
||||||
|
|
||||||
The Javascript console can also be connected to a Geth node using IPC. When Geth is started, a `geth.ipc` file is automatically generated and saved to the data directory. This file, or a custom path to a specific ipc file can be passed to `geth attach` as follows:
|
The Javascript console can also be connected to a Geth node using IPC - in this mode all namespaces are enabled by default. When Geth is started, a `geth.ipc` file is automatically generated and saved to the data directory. This file, or a custom path to a specific ipc file can be passed to `geth attach` as follows:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
geth attach datadir/geth.ipc
|
geth attach datadir/geth.ipc
|
||||||
|
@ -79,11 +78,7 @@ To exit, press ctrl-d or type exit
|
||||||
|
|
||||||
## Interactive use
|
## Interactive use
|
||||||
|
|
||||||
Once the console has been started, it can be used to interact with Geth. The console supports Javascript and the full Geth [JSON-RPC API](/docs/rpc/server). For example, to create an account:
|
Once the console has been started, it can be used to interact with Geth. The console supports Javascript and the full Geth [JSON-RPC API](/docs/rpc/server). For example:
|
||||||
|
|
||||||
```js
|
|
||||||
personal.newAccount()
|
|
||||||
```
|
|
||||||
|
|
||||||
To check the balance of the first account already existing in the keystore:
|
To check the balance of the first account already existing in the keystore:
|
||||||
|
|
||||||
|
@ -91,11 +86,10 @@ To check the balance of the first account already existing in the keystore:
|
||||||
eth.getBalance(personal.listAccounts[0])
|
eth.getBalance(personal.listAccounts[0])
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To send a transaction (without global account unlocking):
|
||||||
To make a transaction (without global account unlocking):
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
personal.sendTransaction({to: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(0.5, "ether")})
|
eth.sendTransaction({to: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(0.5, "ether")})
|
||||||
```
|
```
|
||||||
|
|
||||||
It is also possible to load pre-written Javascript files into the console by passing the `--preload` flag
|
It is also possible to load pre-written Javascript files into the console by passing the `--preload` flag
|
||||||
|
@ -107,7 +101,7 @@ functions.
|
||||||
geth console --preload "/my/scripts/folder/utils.js"
|
geth console --preload "/my/scripts/folder/utils.js"
|
||||||
```
|
```
|
||||||
|
|
||||||
Once the interactive session is over, the console can be closed down by typing `exit` or `CTRL-D`.
|
Once the interactive session is over, the console can be closed down by typing `exit` or `CTRL-D`. Remember that interactions that touch accounts **need approval in Clef** - either manually or by writing a custom ruleset.
|
||||||
|
|
||||||
## Non-interactive Use: Script Mode
|
## Non-interactive Use: Script Mode
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue