website: improved native-bindings with latest code (#29745)

Co-authored-by: Felix Lange <fjl@twurst.com>
pull/29878/head
Mobin Mohanan 4 months ago committed by GitHub
parent 773d79a2d3
commit c6075018f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 32
      docs/developers/dapp-developer/dev-mode.md
  2. 70
      docs/developers/dapp-developer/native-bindings.md

@ -22,9 +22,9 @@ Some basic knowledge of [Solidity](https://docs.soliditylang.org/) and [smart co
## Start Geth in Dev Mode {#start-geth-in-dev-mode} ## Start Geth in Dev Mode {#start-geth-in-dev-mode}
Starting Geth in developer mode is as simple as providing the `--dev` flag. It is also possible to create a realistic block creation frequency by setting `--dev.period 12` instead of creating blocks only when transactions are pending. There are also additional configuration options required to follow this tutorial. Starting Geth in developer mode is as simple as providing the `--dev` flag. It is also possible to create a realistic block creation frequency by setting `--dev.period 12` instead of creating blocks only when transactions are pending. Additional configuration options required to follow this tutorial.
Remix will be used to deploy a smart contract to the node which requires information to be exchanged externally to Geth's own domain. To permit this, enable `http` and the `net` namespace must be enabled and the Remix URL must be provided to `--http.corsdomain`. For this tutorial some other namespaces will also be enabled. The full command is as follows: Remix will be used to deploy a smart contract to the node which requires information to be exchanged externally with Geth's own domain. To permit this, enable `http` and the `net` namespace must be enabled and the Remix URL must be provided to `--http.corsdomain`. Some other namespaces will also be enabled for this tutorial. The full command is as follows:
```sh ```sh
geth --dev --http --http.api eth,web3,net --http.corsdomain "https://remix.ethereum.org" geth --dev --http --http.api eth,web3,net --http.corsdomain "https://remix.ethereum.org"
@ -69,7 +69,7 @@ WARN [05-09|10:49:03.316] Block sealing failed err="sealing
INFO [05-09|10:49:03.316] Commit new sealing work number=1 sealhash=2372a2..7fb8e7 uncles=0 txs=0 gas=0 fees=0 elapsed="540.054µs" INFO [05-09|10:49:03.316] Commit new sealing work number=1 sealhash=2372a2..7fb8e7 uncles=0 txs=0 gas=0 fees=0 elapsed="540.054µs"
``` ```
This terminal must be left running throughout the entire tutorial. In a second terminal, attach a Javascript console. By default the `ipc` file is saved in the `datadir`: This terminal must be left running throughout the entire tutorial. In a second terminal, attach a Javascript console. By default, the `ipc` file is saved in the `datadir`:
```sh ```sh
geth attach <datadir>/geth.ipc geth attach <datadir>/geth.ipc
@ -107,7 +107,7 @@ eth.getBalance(eth.accounts[0])/1e18
web3.fromWei(eth.getBalance(eth.accounts[0])) web3.fromWei(eth.getBalance(eth.accounts[0]))
``` ```
Using `web3.fromWei()` is less error prone because the correct multiplier is built in. These commands both return the following: Using `web3.fromWei()` is less error-prone because the correct multiplier is built in. These commands both return the following:
```terminal ```terminal
1.157920892373162e+59 1.157920892373162e+59
@ -119,7 +119,7 @@ A new account can be created using Clef. Some of the ether from the developer ac
clef newaccount --keystore <path-to-keystore> clef newaccount --keystore <path-to-keystore>
``` ```
The terminal will display a request for a password, twice. Once provided, a new account will be created and its address printed to the terminal. The account creation is also logged in the Geth terminal, including the location of the keyfile in the keystore. It is a good idea to back up the password somewhere at this point. If this were an account on a live network, intended to own assets of real-world value, it would be critical to back up the account password and the keystore in a secure manner. The terminal will display a request for a password, twice. Once provided, a new account will be created, and its address will be printed to the terminal. The account creation is also logged in the Geth terminal, including the location of the keyfile in the keystore. It is a good idea to back up the password somewhere at this point. If this were an account on a live network, intended to own assets of real-world value, it would be critical to back up the account password and the keystore in a secure manner.
To reconfirm the account creation, running `eth.accounts` in the Javascript console should display an array containing two account addresses, one being the developer account and the other being the newly generated address. The following command transfers 50 ETH from the developer account to the new account: To reconfirm the account creation, running `eth.accounts` in the Javascript console should display an array containing two account addresses, one being the developer account and the other being the newly generated address. The following command transfers 50 ETH from the developer account to the new account:
@ -127,7 +127,7 @@ To reconfirm the account creation, running `eth.accounts` in the Javascript cons
eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(50, "ether")}) eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(50, "ether")})
``` ```
A transaction hash will be returned to the console. This transaction hash will also be displayed in the logs in the Geth console, followed by logs confirming that a new block was mined (remember in the local development network blocks are mined when transactions are pending). The transaction details can be displayed in the Javascript console by passing the transaction hash to `eth.getTransaction()`: A transaction hash will be returned to the console. This transaction hash will also be displayed in the logs in the Geth console, followed by logs confirming that a new block was mined (remember, in the local development network, blocks are mined when transactions are pending). The transaction details can be displayed in the Javascript console by passing the transaction hash to `eth.getTransaction()`:
```sh ```sh
eth.getTransaction("0x62044d2cab405388891ee6d53747817f34c0f00341cde548c0ce9834e9718f27") eth.getTransaction("0x62044d2cab405388891ee6d53747817f34c0f00341cde548c0ce9834e9718f27")
@ -160,14 +160,14 @@ The transaction details are displayed as follows:
} }
``` ```
Now that the user account is funded with ether, a contract can be created ready to deploy to the Geth node. Now that the user account is funded with ether, a contract can be created and deployed to the Geth node.
## A simple smart contract {#simple-smart-contract} ## A simple smart contract {#simple-smart-contract}
This tutorial will make use of a classic example smart contract, `Storage.sol`. This contract exposes two public functions, one to add a value to the contract storage and one to view the stored value. The contract, written in Solidity, is provided below: This tutorial will make use of a classic example smart contract, `Storage.sol`. This contract exposes two public functions, one to add a value to the contract storage and one to view the stored value. The contract, written in Solidity, is provided below:
```solidity ```solidity
pragma solidity >=0.8.0; pragma solidity >=0.8.2 <0.9.0;
contract Storage { contract Storage {
uint256 number; uint256 number;
@ -182,15 +182,15 @@ contract Storage {
} }
``` ```
Solidity is a high-level language that makes code executable by the Ethereum virtual machine (EVM) readable to humans. This means that there is an intermediate step between writing code in Solidity and deploying it to Ethereum. This step is called "compilation" and it converts human-readable code into EVM-executable byte-code. This byte-code is then included in a transaction sent from the Geth node during contract deployment. This can all be done directly from the Geth Javascript console; however this tutorial uses an online IDE called Remix to handle the compilation and deployment of the contract to the local Geth node. Solidity is a high-level language that makes code executable by the Ethereum virtual machine (EVM) readable to humans. This means that there is an intermediate step between writing code in Solidity and deploying it to Ethereum. This step is called "compilation", and it converts human-readable code into EVM-executable bytecode. This byte-code is then included in a transaction sent from the Geth node during contract deployment. This can all be done directly from the Geth Javascript console; however, this tutorial uses an online IDE called Remix to handle the compilation and deployment of the contract to the local Geth node.
## Compile and deploy using Remix {#compile-and-deploy} ## Compile and deploy using Remix {#compile-and-deploy}
In a web browser, open <https://remix.ethereum.org>. This opens an online smart contract development environment. On the left-hand side of the screen there is a side-bar menu that toggles between several toolboxes that are displayed in a vertical panel. On the right hand side of the screen there is an editor and a terminal. This layout is similar to the default layout of many other IDEs such as [VSCode](https://code.visualstudio.com/). The contract defined in the previous section, `Storage.sol` is already available in the `Contracts` directory in Remix. It can be opened and reviewed in the editor. In a web browser, open <https://remix.ethereum.org>. This opens an online smart contract development environment. On the left-hand side of the screen there is a side-bar menu that toggles between several toolboxes that are displayed in a vertical panel. On the right-hand side of the screen, there is an editor and a terminal. This layout is similar to the default layout of many other IDEs such as [VSCode](https://code.visualstudio.com/). The contract defined in the previous section, `Storage.sol` is already available in the `Contracts` directory in Remix. It can be opened and reviewed in the editor.
![Remix](/images/docs/remix.png) ![Remix](/images/docs/remix.png)
The Solidity logo is present as an icon in the Remix side-bar. Clicking this icon opens the Solidity compiler wizard. This can be used to compile `Storage.sol` ready. With `Solidity.sol` open in the editor window, simply click the `Compile 1_Storage.sol` button. A green tick will appear next to the Solidity icon to confirm that the contract has compiled successfully. This means the contract bytecode is available. The Solidity logo is present as an icon in the Remix sidebar. Clicking this icon opens the Solidity compiler wizard, which can be used to compile `Storage.sol` ready. With `Solidity.sol` open in the editor window, simply click the `Compile 1_Storage.sol` button. A green tick will appear next to the Solidity icon to confirm that the contract has been compiled successfully. This means the contract bytecode is available.
![Remix-compiler](/images/docs/remix-compiler.png) ![Remix-compiler](/images/docs/remix-compiler.png)
@ -212,7 +212,7 @@ INFO [05-09|12:27:09.681] 🔨 mined potential block number=2 h
## Interact with contract using Remix {#interact-with-contract} ## Interact with contract using Remix {#interact-with-contract}
The contract is now deployed on a local testnet version of the Ethereum blockchain. This means there is a contract address that contains executable bytecode that can be invoked by sending transactions with instructions, also in bytecode, to that address. Again, this can all be achieved by constructing transactions directly in the Geth console or even by making external http requests using tools such as Curl. Here, Remix is used to retrieve the value, then the same action is taken using the Javascript console. The contract is now deployed on a local testnet version of the Ethereum blockchain. This means there is a contract address that contains an executable bytecode that can be invoked by sending transactions with instructions, also in bytecode, to that address. Again, this can all be achieved by constructing transactions directly in the Geth console or even by making external http requests using tools such as Curl. Here, Remix is used to retrieve the value; then the same action is taken using the Javascript console.
After deploying the contract in Remix, the `Deployed Contracts` tab in the sidebar automatically populates with the public functions exposed by `Storage.sol`. To send a value to the contract storage, type a number in the field adjacent to the `store` button, then click the button. After deploying the contract in Remix, the `Deployed Contracts` tab in the sidebar automatically populates with the public functions exposed by `Storage.sol`. To send a value to the contract storage, type a number in the field adjacent to the `store` button, then click the button.
@ -254,7 +254,7 @@ The transaction hash can be used to retrieve the transaction details using the G
} }
``` ```
The `from` address is the account that sent the transaction, the `to` address is the deployment address of the contract. The value entered into Remix is now in storage at that contract address. This can be retrieved using Remix by calling the `retrieve` function - to do this simply click the `retrieve` button. Alternatively, it can be retrieved using `web3.getStorageAt` using the Geth Javascript console. The following command returns the value in the contract storage (replace the given address with the correct one displayed in the Geth logs). The `from` address is the account that sent the transaction, and the `to` address is the deployment address of the contract. The value entered into Remix is now in storage at that contract address. This can be retrieved using Remix by calling the `retrieve` function - to do this simply click the `retrieve` button. Alternatively, it can be retrieved using `web3.getStorageAt` using the Geth Javascript console. The following command returns the value in the contract storage (replace the given address with the correct one displayed in the Geth logs).
```sh ```sh
web3.eth.getStorageAt("0x407d73d8a49eeb85d32cf465507dd71d507100c1", 0) web3.eth.getStorageAt("0x407d73d8a49eeb85d32cf465507dd71d507100c1", 0)
@ -278,7 +278,7 @@ geth --datadir dev-chain --dev --http --http.api web3,eth,net --http.corsdomain
## Re-using accounts {#reusing-accounts} ## Re-using accounts {#reusing-accounts}
Geth will fail to start in dev-mode if keys have been manually created or imported into the keystore in the `--datadir` directory. This is because the account cannot be automatically unlocked. To resolve this issue, the password defined when the account was created can be saved to a text file and its path passed to the `--password` flag on starting Geth, for example if `password.txt` is saved in the top-level `go-ethereum` directory: Geth will fail to start in dev-mode if keys have been manually created or imported into the keystore in the `--datadir` directory. This is because the account cannot be automatically unlocked. To resolve this issue, the password defined when the account was created can be saved to a text file and its path passed to the `--password` flag on starting Geth, for example, if `password.txt` is saved in the top-level `go-ethereum` directory:
```sh ```sh
geth --datadir dev-chain --dev --http --http.api web3,eth,net --http.corsdomain "https://remix.ethereum.org" --password password.txt geth --datadir dev-chain --dev --http --http.api web3,eth,net --http.corsdomain "https://remix.ethereum.org" --password password.txt
@ -288,8 +288,8 @@ geth --datadir dev-chain --dev --http --http.api web3,eth,net --http.corsdomain
It is possible to use a custom genesis block configuration in development mode. To obtain a compatible configuration, run `geth --dev dumpgenesis`. The resulting genesis has proof-of-stake and all pre-merge hard forks activated at block 0. Precompile addresses are funded to prevent them being removed from the state per EIP158. It is possible to use a custom genesis block configuration in development mode. To obtain a compatible configuration, run `geth --dev dumpgenesis`. The resulting genesis has proof-of-stake and all pre-merge hard forks activated at block 0. Precompile addresses are funded to prevent them being removed from the state per EIP158.
Users are free to modify the generated template provided they keep pre-merge hard-forks and proof-of-stake transition activated at block 0. Users are free to modify the generated template provided they keep the pre-merge hard-forks and proof-of-stake transition activated at block 0.
## Summary {#summary} ## Summary {#summary}
This tutorial has demonstrated how to spin up a local developer network using Geth. Having started this development network, a simple contract was deployed to the developer network. Then, Remix was connected to the local Geth node and used to deploy and interact with a contract. Remix was used to add a value to the contract storage and then the value was retrieved using Remix and also using the lower level commands in the Javascript console. This tutorial has demonstrated how to spin up a local developer network using Geth. Having started this development network, a simple contract was deployed to the developer network. Then, Remix was connected to the local Geth node and used to deploy and interact with a contract. Remix was used to add a value to the contract storage, and then the value was retrieved using Remix and also using the lower-level commands in the Javascript console.

@ -3,9 +3,9 @@ title: Go Contract Bindings
description: Introduction to generating bindings for using Geth features in Go native applications description: Introduction to generating bindings for using Geth features in Go native applications
--- ---
This page introduces the concept of server-side native dapps. Geth provides the tools required to generate [Go](https://github.com/golang/go/wiki#getting-started-with-go) language bindings to any Ethereum contract that is compile-time type safe, highly performant and can be generated completely automatically from a compiled contract. This page introduces the concept of server-side native dapps. Geth provides the tools required to generate [Go](https://github.com/golang/go/wiki#getting-started-with-go) language bindings to any Ethereum contract that is compile-time type-safe, highly performant, and can be generated completely automatically from a compiled contract.
Interacting with a contract on the Ethereum blockchain from Go is already possible via the RPC interfaces exposed by Ethereum clients. However, writing the boilerplate code that translates Go language constructs into RPC calls and back is time consuming and brittle - implementation bugs can only be detected during runtime and it's almost impossible to evolve a contract as even a tiny change in Solidity is awkward to port over to Go. Therefore, Geth provides tools for easily converting contract code into Go code that can be used directly in Go applications. Interacting with a contract on the Ethereum blockchain from Go is already possible via the RPC interfaces exposed by Ethereum clients. However, writing the boilerplate code that translates Go language constructs into RPC calls and back is time-consuming and brittle - implementation bugs can only be detected during runtime, and it's almost impossible to evolve a contract as even a tiny change in Solidity is awkward to port over to Go. Therefore, Geth provides tools for easily converting contract code into Go code that can be used directly in Go applications.
This page provides an introduction to generating Go contract bindings and using them in a simple Go application. This page provides an introduction to generating Go contract bindings and using them in a simple Go application.
@ -15,11 +15,11 @@ This page is fairly beginner-friendly and designed for people starting out with
## What is an ABI? {#what-is-an-abi} ## What is an ABI? {#what-is-an-abi}
Ethereum smart contracts have a schema that defines its functions and return types in the form of a JSON file. This JSON file is known as an _Application Binary Interface_, or ABI. The ABI acts as a specification for precisely how to encode data sent to a contract and how to decode the data the contract sends back. The ABI is the only essential piece of information required to generate Go bindings. Go developers can then use the bindings to interact with the contract from their Go application without having to deal directly with data encoding and decoding. An ABI is generated when a contract is compiled. Ethereum smart contracts have a schema that defines its functions and returns types as a JSON file. This JSON file is known as an _Application Binary Interface_, or ABI. The ABI acts as a specification for precisely how to encode data sent to a contract and how to decode the data the contract sends back. The ABI is the only essential piece of information required to generate Go bindings. Go developers can then use the bindings to interact with the contract from their Go application without having to deal directly with data encoding and decoding. An ABI is generated when a contract is compiled.
## Abigen: Go binding generator {#abigen} ## Abigen: Go binding generator {#abigen}
Geth includes a source code generator called `abigen` that can convert Ethereum ABI definitions into easy to use, type-safe Go packages. With a valid Go development environment set up and the go-ethereum repository checked out correctly, `abigen` can be built as follows: Geth includes a source code generator called `abigen` that can convert Ethereum ABI definitions into easy-to-use, type-safe Go packages. With a valid Go development environment set up and the go-ethereum repository checked out correctly, `abigen` can be built as follows:
```sh ```sh
go install github.com/ethereum/go-ethereum/cmd/abigen@latest go install github.com/ethereum/go-ethereum/cmd/abigen@latest
@ -27,7 +27,7 @@ go install github.com/ethereum/go-ethereum/cmd/abigen@latest
### Generating the bindings {#generating-bindings} ### Generating the bindings {#generating-bindings}
To demonstrate the binding generator a contract is required. The contract `Storage.sol` implements two very simple functions: `store` updates a user-defined `uint256` to the contract's storage, and `retrieve` displays the value stored in the contract to the user. The Solidity code is as follows: A contract is required to demonstrate the binding generator. The contract `Storage.sol` implements two very simple functions: `store` updates a user-defined `uint256` to the contract's storage, and `retrieve` displays the value stored in the contract to the user. The Solidity code is as follows:
```solidity ```solidity
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
@ -35,7 +35,7 @@ To demonstrate the binding generator a contract is required. The contract `Stora
pragma solidity >0.7.0 < 0.9.0; pragma solidity >0.7.0 < 0.9.0;
/** /**
* @title Storage * @title Storage
* @dev store or retrieve variable value * @dev store or retrieve a variable value
*/ */
contract Storage { contract Storage {
@ -60,7 +60,7 @@ The following code snippet shows how an ABI can be generated for `Storage.sol` u
solc --abi Storage.sol -o build solc --abi Storage.sol -o build
``` ```
The ABI can also be generated in other ways such as using the `compile` commands in development frameworks such as [Truffle](https://trufflesuite.com/docs/truffle/), [Hardhat](https://hardhat.org/) and [Brownie](https://eth-brownie.readthedocs.io/en/stable/) or in the online IDE [Remix](https://remix.ethereum.org/). ABIs for existing verified contracts can be downloaded from [Etherscan](https://etherscan.io/). The ABI can also be generated in other ways such as using the `compile` commands in development frameworks such as [Foundry](https://book.getfoundry.sh/), [Hardhat](https://hardhat.org/) and [Brownie](https://eth-brownie.readthedocs.io/en/stable/) or in the online IDE [Remix](https://remix.ethereum.org/). ABIs for existing verified contracts can be downloaded from [Etherscan](https://etherscan.io/).
The ABI for `Storage.sol` (`Storage.abi`) looks as follows: The ABI for `Storage.sol` (`Storage.abi`) looks as follows:
@ -148,7 +148,7 @@ type Storage struct {
``` ```
`Storage.go` contains all the bindings required to interact with `Storage.sol` from a Go application. However, this isn't very useful unless the contract is actually deployed on Ethereum or one of Ethereum's testnets. The following sections will demonstrate how to deploy the contract to `Storage.go` contains all the bindings required to interact with `Storage.sol` from a Go application. However, this isn't very useful unless the contract is deployed on Ethereum or one of Ethereum's testnets. The following sections will demonstrate how to deploy the contract to
an Ethereum testnet and interact with it using the Go bindings. an Ethereum testnet and interact with it using the Go bindings.
### Deploying contracts to Ethereum {#deploying-contracts} ### Deploying contracts to Ethereum {#deploying-contracts}
@ -218,12 +218,17 @@ import (
const key = `<<json object from keystore>>` const key = `<<json object from keystore>>`
func main() { func main() {
// Create an IPC based RPC connection to a remote node and an authorized transactor // Create an IPC-based RPC connection to a remote node and an authorized transactor
conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc") conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc")
if err != nil { if err != nil {
log.Fatalf("Failed to connect to the Ethereum client: %v", err) log.Fatalf("Failed to connect to the Ethereum client: %v", err)
} }
auth, err := bind.NewTransactorWithChainID(strings.NewReader(key), "<<strong_password>>", ChainId) // Retrieve the current chain ID
chainID, err := conn.ChainID(context.Background())
if err != nil {
log.Fatal("Failed to retrieve chain ID: %v", err)
}
auth, err := bind.NewTransactorWithChainID(strings.NewReader(key), "<<strong_password>>", chainID)
if err != nil { if err != nil {
log.Fatalf("Failed to create authorized transactor: %v", err) log.Fatalf("Failed to create authorized transactor: %v", err)
} }
@ -271,12 +276,12 @@ Note that `DeployStorage` returns four variables:
To interact with a contract already deployed on the blockchain, the deployment `address` is required and a `backend` through which to access Ethereum must be defined. The binding generator provides an RPC backend out-of-the-box that can be used to attach to an existing Ethereum node via IPC, HTTP or WebSockets. To interact with a contract already deployed on the blockchain, the deployment `address` is required and a `backend` through which to access Ethereum must be defined. The binding generator provides an RPC backend out-of-the-box that can be used to attach to an existing Ethereum node via IPC, HTTP or WebSockets.
As in the previous section, a Geth node running on an Ethereum testnet (recommend Goerli) and an account with some test ETH to cover gas is required. The `Storage.sol` deployment address is also needed. As in the previous section, a Geth node running on an Ethereum testnet (recommend Goerli) and an account with some test ETH to cover gas are required. The `Storage.sol` deployment address is also needed.
Again, an instance of `ethclient` can be created, passing the path to Geth's ipc file. In the example below this backend is assigned to the variable `conn`. Again, an instance of `ethclient` can be created, passing the path to Geth's ipc file. In the example below this backend is assigned to the variable `conn`.
```go ```go
// Create an IPC based RPC connection to a remote node // Create an IPC-based RPC connection to a remote node
// NOTE update the path to the ipc file! // NOTE update the path to the ipc file!
conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc") conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc")
if err != nil { if err != nil {
@ -311,7 +316,7 @@ import (
) )
func main() { func main() {
// Create an IPC based RPC connection to a remote node // Create an IPC-based RPC connection to a remote node
// NOTE update the path to the ipc file! // NOTE update the path to the ipc file!
conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc") conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc")
if err != nil { if err != nil {
@ -326,7 +331,7 @@ func main() {
``` ```
The contract instance is then available to interact with in the Go application. To read a value from the blockchain, for example the `value` stored in the contract, the contract's `Retrieve()` function can be called. Again, the function is defined in `Storage.go` as follows: The contract instance is then available to interact with in the Go application. To read a value from the blockchain, for example, the `value` stored in the contract, the contract's `Retrieve()` function can be called. Again, the function is defined in `Storage.go` as follows:
```go ```go
// Retrieve is a free data retrieval call binding the contract method 0x2e64cec1. // Retrieve is a free data retrieval call binding the contract method 0x2e64cec1.
@ -347,9 +352,9 @@ func (_Storage *StorageCaller) Retrieve(opts *bind.CallOpts) (*big.Int, error) {
} }
``` ```
Note that the `Retrieve()` function requires a parameter to be passed, even though the original Solidity contract didn't require any at all none. The parameter required is a `*bind.CallOpts` type, which can be used to fine tune the call. If no adjustments to the call are required, pass `nil`. Adjustments to the call include: Note that the `Retrieve()` function requires a parameter to be passed, even though the original Solidity contract didn't require any at all none. The parameter required is a `*bind.CallOpts` type, which can be used to fine-tune the call. If no adjustments to the call are required, pass `nil`. Adjustments to the call include:
- `Pending`: Whether to access pending contract state or the current stable one - `Pending`: Whether to access the pending contract state or the current stable one
- `GasLimit`: Place a limit on the computing resources the call might consume - `GasLimit`: Place a limit on the computing resources the call might consume
So to call the `Retrieve()` function in the Go application: So to call the `Retrieve()` function in the Go application:
@ -371,9 +376,9 @@ Value: 56
### Transacting with an Ethereum contract {#transacting-with-contract} ### Transacting with an Ethereum contract {#transacting-with-contract}
Invoking a method that changes contract state (i.e. transacting) is a bit more involved, as a live transaction needs to be authorized and broadcast into the network. **Go bindings require local signing of transactions and do not delegate this to a remote node.** This is to keep accounts private within dapps, and not shared (by default) between them. Invoking a method that changes contract state (i.e. transacting) is a bit more involved, as a live transaction needs to be authorized and broadcast into the network. **Go bindings require local signing of transactions, so do not delegate this to a remote node.** This is to keep accounts private within dapps, and not shared (by default) between them.
Thus to allow transacting with a contract, your code needs to implement a method that given an input transaction, signs it and returns an authorized output transaction. Since most users have their keys in the [Web3 Secret Storage](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) format, the `bind` package contains a small utility method (`bind.NewTransactor(keyjson, passphrase)`) that can create an authorized transactor from a key file and associated password, without the user needing to implement key signing themselves. Thus, to allow transacting with a contract, your code needs to implement a method that gives an input transaction, signs it and returns an authorized output transaction. Since most users have their keys in the [Web3 Secret Storage](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) format, the `bind` package contains a small utility method (`bind.NewTransactor(keyjson, passphrase)`) that can create an authorized transactor from a key file and associated password, without the user needing to implement key signing themselves.
Changing the previous code snippet to update the value stored in the contract: Changing the previous code snippet to update the value stored in the contract:
@ -391,7 +396,7 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
) )
const key = `json object from keystore` const key = `<<json object from keystore>>`
func main() { func main() {
// Create an IPC based RPC connection to a remote node and instantiate a contract binding // Create an IPC based RPC connection to a remote node and instantiate a contract binding
@ -403,8 +408,13 @@ func main() {
if err != nil { if err != nil {
log.Fatalf("Failed to instantiate a Storage contract: %v", err) log.Fatalf("Failed to instantiate a Storage contract: %v", err)
} }
// Retrieve the current chain ID
chainID, err := conn.ChainID(context.Background())
if err != nil {
log.Fatal("Failed to retrieve chain ID: %v", err)
}
// Create an authorized transactor and call the store function // Create an authorized transactor and call the store function
auth, err := bind.NewStorageTransactor(strings.NewReader(key), "strong_password") auth, err := bind.NewTransactorWithChainID(strings.NewReader(key), "<<strong_password>>", chainID)
if err != nil { if err != nil {
log.Fatalf("Failed to create authorized transactor: %v", err) log.Fatalf("Failed to create authorized transactor: %v", err)
} }
@ -423,7 +433,7 @@ And the output:
Update pending: 0x4f4aaeb29ed48e88dd653a81f0b05d4df64a86c99d4e83b5bfeb0f0006b0e55b Update pending: 0x4f4aaeb29ed48e88dd653a81f0b05d4df64a86c99d4e83b5bfeb0f0006b0e55b
``` ```
Similar to the method invocations in the previous section which only read contract state, transacting methods also require a mandatory first parameter, a `*bind.TransactOpts` type, which authorizes the transaction and potentially fine tunes it: Similar to the method invocations in the previous section which only read contract state, transacting methods also require a mandatory first parameter, a `*bind.TransactOpts` type, which authorizes the transaction and potentially fine-tunes it:
- `From`: Address of the account to invoke the method with (mandatory) - `From`: Address of the account to invoke the method with (mandatory)
- `Signer`: Method to sign a transaction locally before broadcasting it (mandatory) - `Signer`: Method to sign a transaction locally before broadcasting it (mandatory)
@ -436,9 +446,9 @@ The two mandatory fields are automatically set by the `bind` package if the auth
### Pre-configured contract sessions {#preconfigured-sessions} ### Pre-configured contract sessions {#preconfigured-sessions}
Reading and state modifying contract-calls require a mandatory first parameter which can authorize and fine tune some of the internal parameters. However, most of the time the same accounts and parameters will be used to issue many transactions, so constructing the call/transact options individually quickly becomes unwieldy. Reading and state-modifying contract calls require a mandatory first parameter that can authorize and fine-tune some of the internal parameters. However, the same accounts and parameters will usually be used to issue many transactions, so constructing the call/transact options individually quickly becomes unwieldy.
To avoid this, the generator also creates specialized wrappers that can be pre-configured with tuning and authorization parameters, allowing all the Solidity defined methods to be invoked without needing an extra parameter. To avoid this, the generator also creates specialized wrappers that can be pre-configured with tuning and authorization parameters, allowing all the Solidity-defined methods to be invoked without needing an extra parameter.
These are named similarly to the original contract type name but suffixed with `Sessions`: These are named similarly to the original contract type name but suffixed with `Sessions`:
@ -461,7 +471,7 @@ session.Store(big.NewInt(69))
## Bind Solidity directly {#binding-solidity} ## Bind Solidity directly {#binding-solidity}
In the past, abigen allowed compilation and binding of a Solidity source file directly to a Go package in a single step. This feature has been discontinued from [v1.10.18](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.18) onwards due to maintenance synchronization challenges with the compiler in Geth. In the past, abigen allowed the compilation and binding of a Solidity source file directly to a Go package in a single step. This feature has been discontinued from [v1.10.18](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.18) onwards due to maintenance synchronization challenges with the compiler in Geth.
The compilation and binding steps can be joined together into a pipeline, for example: The compilation and binding steps can be joined together into a pipeline, for example:
@ -471,7 +481,7 @@ solc Storage.sol --combined-json abi,bin | abigen --pkg main --type storage --ou
### Project integration (`go generate`) {#project-integration} ### Project integration (`go generate`) {#project-integration}
The `abigen` command was made in such a way as to integrate easily into existing Go toolchains: instead of having to remember the exact command needed to bind an Ethereum contract into a Go project, `go generate` can handle all the fine details. The `abigen` command was designed to integrate easily into existing Go toolchains: instead of having to remember the exact command needed to bind an Ethereum contract to a Go project, `go generate` can handle all the fine details.
Place the binding generation command into a Go source file before the package definition: Place the binding generation command into a Go source file before the package definition:
@ -479,11 +489,11 @@ Place the binding generation command into a Go source file before the package de
//go:generate abigen --sol Storage.sol --pkg main --out Storage.go //go:generate abigen --sol Storage.sol --pkg main --out Storage.go
``` ```
After which whenever the Solidity contract is modified, instead of needing to remember and run the above command, we can simply call `go generate` on the package (or even the entire source tree via `go generate ./...`), and it will correctly generate the new bindings for us. After that, whenever the Solidity contract is modified, instead of remembering and running the above command, we can simply call `go generate` on the package (or even the entire source tree via `go generate ./...`), and it will correctly generate the new bindings for us.
## Blockchain simulator {#blockchain-simulator} ## Blockchain simulator {#blockchain-simulator}
Being able to deploy and access deployed Ethereum contracts from native Go code is a powerful feature. However, using public testnets as a backend does not lend itself well to _automated unit testing_. Therefore, Geth also implements a _simulated blockchain_ that can be set as a backend to native contracts the same way as a live RPC backend, using the command `simulated.NewBackend(map[common.Address]core.GenesisAccount)`. The code snippet below shows how this can be used as a backend in a Go application. Being able to deploy and access deployed Ethereum contracts from native Go code is a powerful feature. However, using public testnets as a backend does not lend itself well to _automated unit testing_. Therefore, Geth also implements a _simulated blockchain_ that can be set as a backend to native contracts like a live RPC backend, using the command `simulated.NewBackend(map[common.Address]core.GenesisAccount)`. The code snippet below shows how this can be used as a backend in a Go application.
```go ```go
package main package main
@ -495,7 +505,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient/simulated" "github.com/ethereum/go-ethereum/ethclient/simulated"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -507,7 +517,7 @@ func main() {
log.Fatalf("Failed to generate key: %v", err) log.Fatalf("Failed to generate key: %v", err)
} }
// Since we are using a simulated backend, we will get the chain id // Since we are using a simulated backend, we will get the chain ID
// from the same place that the simulated backend gets it. // from the same place that the simulated backend gets it.
chainID := params.AllDevChainProtocolChanges.ChainID chainID := params.AllDevChainProtocolChanges.ChainID
@ -516,7 +526,7 @@ func main() {
log.Fatalf("Failed to make transactor: %v", err) log.Fatalf("Failed to make transactor: %v", err)
} }
sim := simulated.NewBackend(map[common.Address]core.GenesisAccount{ sim := simulated.NewBackend(map[common.Address]types.Account{
auth.From: {Balance: big.NewInt(9e18)}, auth.From: {Balance: big.NewInt(9e18)},
}) })

Loading…
Cancel
Save