[JAVA] Introduction to web3j

web3j is a Java library that can communicate with Ethereum clients (nodes) via JSON-RPC. In this article, I will introduce the basic usage of web3j.


Topic

  1. Connect to Ethereum client
  2. Communicate with Ethereum client via JSON-RPC
    1. web3_clientVersion
    2. eth_getBlockByNumber
    3. eth_sendTransaction
  3. Introduction of useful functions
  4. Processing using a wallet file
  5. Contract wrapper class
  6. Handle events reactively

Connecting to Ethereum client

First, start the Ethereum client and enable JSON-RPC communication. For example, start Geth to enable JSON-RPC communication via HTTP.

When you're ready, use web3j to connect to your Ethereum client.

//HTTP connection
Web3j web3j = Web3j.build(new HttpService("http://<ip address>:<port>"));

//IPC connection(Unix)
Web3j web3 = Web3j.build(new UnixIpcService("/path/to/socketfile"));

//IPC connection(Windows)
Web3j web3 = Web3j.build(new WindowsIpcService("/path/to/namedpipefile"));

Communicate with Ethereum client via JSON-RPC

After successfully connecting to the Ethereum client, let's communicate with JSON-RPC. JSON-RPC communication with web3j is very easy.

web3_clientVersion For example, to call the JSON-RPC web3_clientVersion method, write as follows. (Web3_clientVersion is a method to check the version of Ethereum client)

//Connect with Ethereum client
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));
// JSON-Send RPC request and receive response
Web3ClientVersion response = web3j.web3ClientVersion().send();
//Output result
System.out.println(response.getResult());

output(Example)


Geth/v1.8.17-stable-8bbe7207/windows-amd64/go1.11.1

As you can see, web3j provides its own Java method for requesting each JSON-RPC method.

eth_getBlockByNumber The following is an example where you need to specify method arguments. Here, let's use the JSON-RPC ʻeth_getBlockByNumber` method to get the latest ("latest") block information.

//Connect with Ethereum client
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));
// JSON-Send RPC request and receive response
EthBlock response = web3j.ethGetBlockByNumber(
    DefaultBlockParameterName.LATEST, //block number. Here is a tag that represents the latest block"latest"To specify
    false //If true, get transaction details. If false, get only transaction hash
    ).send();
//Output result
Block block = response.getResult();
System.out.println("hash:" + block.getHash());
System.out.println("number:" + block.getNumber());

output(Example)


hash:0x7abc74f4b77054a378cd8969b77ca207ed74ff925bd751314186180d37818d33
number:7311

In this way, method arguments can also be specified according to the JSON-RPC specifications, so it's very easy to understand.

eth_sendTransaction The following is an example that involves issuing a transaction. Here, let's send Ether using JSON-RPC ʻeth_sendTransaction`.

But before that, you need to unlock your account. If the Ethereum client is Geth, JSON-RPC provides a personal_unlockAccount method, so use this to unlock your account and then send Ether.

//Connect with Ethereum client
//Admin is a subclass of Web3j"personal_unlockAccount"Request processing is implemented.
Admin web3j = Admin.build(new HttpService("http://localhost:8545"));

// "personal_unlockAccount"Send a request and receive a response
PersonalUnlockAccount unlockAccountResponse = web3j.personalUnlockAccount(
    "0x766a1c4737970feddde6f2b8659fca05bd0339ab", //address
    "pass1" //password
    ).send();

//If the unlock is successful, send Ether
if (unlockAccountResponse.getResult()) {
    // "eth_sendTransaction"Create an object to pass to the argument of
    Transaction transaction = Transaction.createEtherTransaction(
        "0x766a1c4737970feddde6f2b8659fca05bd0339ab", // from
        null, //nonce. Not specified this time, so null
        null, //gasPrice. Not specified this time, so null
        null, //gas Limit. Not specified this time, so null
        "0x0cbc0fe59d39e58d7369ca436fe5c6b4b71341d5", // to
        BigInteger.valueOf(100) // value
        );
    
    // "eth_sendTransaction"Send a request and receive a response
    EthSendTransaction sendTransactionResponse = web3j.ethSendTransaction(transaction).send();
    //Output result
    System.out.println(sendTransactionResponse.getResult());
}

output(Example)


0x3557db13b5ac56f1e3e23ab9eeccd11b2c4daf73e416496d53c5bba377202a61

Introduction of useful functions

web3j offers useful features that go beyond simply calling JSON-RPC methods. Here, we will introduce the following three functions.

--Processing using a wallet file --Contract wrapper class --Process events reactively

Processing using a wallet file

What is a wallet file? You might think that. This is what is called a "key file" in Geth. The key file is created when you run geth account new. Normally, in Geth, the key file is placed in" \ <datadir > / keystore ". This "key file" is called a "Wallet file" in web3j.

In web3j, the process related to unlocking the account is simplified by using the wallet file. Here, let's send Ether using a wallet file.

First, place (copy) the wallet file in a location that can be accessed from the environment in which the web3j program is executed. When you're ready, use your wallet file to send Ether.

//Connect with Ethereum client
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Load wallet file
Credentials credentials = WalletUtils.loadCredentials(
    "pass1", //Account password
    "/pass/to/walletfile"
    );

//Send Ether
TransactionReceipt receipt = Transfer.sendFunds(
    web3j,
    credentials,
    "0xdc87fc3ac1ec09ed43623dd9da4c6f3d792a88f5", // to
    new BigDecimal("1000"), // value
    Unit.ETHER // unit
    ).send();

Once you load the wallet file, you can use it as many times as you like. If you want to issue multiple transactions, you don't have to request personal_unlockAccount multiple times, which simplifies the process.

Contract wrapper class

web3j provides a tool (command line tool) to generate a wrapper class for contracts. Wrapper classes make contract deployment and method invocation very simple. (Of course, it is also possible to request JSON-RPC ʻeth_sendTransaction or ʻeth_call to deploy the contract or call the method without using the wrapper class.)

Here, as a sample, the wrapper class of the following source written in Solidity is generated.

Token.sol


pragma solidity ^0.5.0;

contract Token {
    uint256 public totalSupply;
    mapping (address => uint256) public balanceOf;

    constructor (uint256 _initialSupply) public {
        totalSupply = _initialSupply;
        balanceOf[msg.sender] = _initialSupply;
    }

    function transfer(address _to, uint256 _value) public {
        require(balanceOf[msg.sender] >= _value);
        require(balanceOf[_to] + _value >= balanceOf[_to]);
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
    }
}

First, compile the source using Online Compiler. You can get the ABI and bytecode by compiling the source. Save the obtained ABI and bytecode to a file.

In the sample, I saved the ABI and bytecode to a file as follows.

Token.abi


[{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_initialSupply","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]

Token.bin


0x608060405234801561001057600080fd5b506040516020806103a28339810180604052602081101561003057600080fd5b81019080805190602001909291905050508060008190555080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550506103068061009c6000396000f3fe608060405260043610610051576000357c01000000000000000000000000000000000000000000000000000000009004806318160ddd1461005657806370a0823114610081578063a9059cbb146100e6575b600080fd5b34801561006257600080fd5b5061006b610141565b6040518082815260200191505060405180910390f35b34801561008d57600080fd5b506100d0600480360360208110156100a457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610147565b6040518082815260200191505060405180910390f35b3480156100f257600080fd5b5061013f6004803603604081101561010957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061015f565b005b60005481565b60016020528060005260406000206000915090505481565b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101ad57600080fd5b600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054011015151561023c57600080fd5b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550505056fea165627a7a72305820f97c3c938c56e1b594db9c9b681f3a08bb4ef81ef0fa5888d5982034167a44ba0029

Next, get the command line tools. You can download the command line tools from the GitHub Release Page (https://github.com/web3j/web3j/releases).

Unzip the downloaded compressed file and execute the executable file under the bin directory as follows.

web3j solidity generate -a=/path/to/Token.abi -b=/path/to/Token.bin -o=/path/to/src/main/java -p=package.name

If the command is successful, a wrapper class with the name "Token.java" will be generated in the directory specified by -o and -p.

Now that we're ready, let's use the wrapper class to deploy the contract and call the method.

//Connect with Ethereum client
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Load wallet file
Credentials credentials = WalletUtils.loadCredentials(
    "pass1", //Account password
    "/pass/to/walletfile"
    );	

//Deploy contract
Token token = Token.deploy(
    web3j,
    credentials,
    BigInteger.valueOf(1000000000L), // gasPrice
    BigInteger.valueOf(4700000L), // gasLimit
    BigInteger.valueOf(100000000000L) //initialSupply (constructor argument)
    ).send();

//Output the address of the contract
System.out.println("contract address: " + token.getContractAddress());

//Method call (no transaction)
System.out.println("totalSupply: " + token.totalSupply().send());
System.out.println("balance of user1: " + token.balanceOf("0x766a1c4737970feddde6f2b8659fca05bd0339ab").send());

//Method call (with transaction)
System.out.println("Sending ether to user2...");
TransactionReceipt tran = token.transfer("0xdc87fc3ac1ec09ed43623dd9da4c6f3d792a88f5", BigInteger.valueOf(1000L)).send();

//Result output
System.out.println("transaction hash: " + tran.getTransactionHash());
System.out.println("balance of user1: " + token.balanceOf("0x766a1c4737970feddde6f2b8659fca05bd0339ab").send());
System.out.println("balance of user2: " + token.balanceOf("0xdc87fc3ac1ec09ed43623dd9da4c6f3d792a88f5").send());

output(Example)


contract address: 0x7b1530efbcbc4e9588fea3e505a95a3aeb84f3ed
totalSupply: 100000000000
balance of user1: 100000000000
Sending ether to user2...
transaction hash: 0x47cea479cd5aa3b4fc2fda5a0fcf6f5edc83ad2692a10355338b43aad9de41ef
balance of user1: 99999999000
balance of user2: 1000

You can see that the contract deployment and method invocation can be described very simply.

Handle events reactively

Finally, I will introduce the event monitoring function. web3j provides the ability to handle Ethereum events reactively.

Event monitoring using JSON-RPC usually involves first registering a filter using ʻeth_newBlockFilter, ʻeth_newFilter, etc., and then polling the event using ʻeth_getFilterChanges`. .. This is very troublesome, isn't it?

By using the function provided by web3j, event monitoring can be described as follows.

//Connect with Ethereum client
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Register filter (start event monitoring)
Disposable disposable = web3j.blockFlowable(false).subscribe(ethBlock -> {
    //When a new block occurs, perform the following processing
    Block block = ethBlock.getBlock();
    System.out.println(block.getNumber());
});

//Remove filter (end event monitoring)
disposable.dispose();

It's very simple to write.

Recommended Posts

Introduction to web3j
Introduction to Ruby 2
Introduction to SWING
Introduction to Micronaut 1 ~ Introduction ~
[Java] Introduction to Java
Introduction to migration
Introduction to java
Introduction to Doma
Introduction to JAR files
Introduction to Ratpack (8)-Session
Introduction to RSpec 1. Test, RSpec
Introduction to bit operation
Introduction to Ratpack (6) --Promise
Introduction to Ratpack (9) --Thymeleaf
Introduction to PlayFramework 2.7 ① Overview
Introduction to Android Layout
Introduction to design patterns (introduction)
Introduction to Practical Programming
Introduction to javadoc command
Introduction to jar command
Introduction to Ratpack (2)-Architecture
Introduction to lambda expression
Introduction to java command
Introduction to RSpec 2. RSpec setup
Introduction to Keycloak development
Introduction to javac command
Introduction to Design Patterns (Builder)
Introduction to RSpec 5. Controller specs
Introduction to RSpec 6. System specifications
Introduction to RSpec 3. Model specs
Introduction to Ratpack (5) --Json & Registry
Introduction to Metabase ~ Environment Construction ~
Introduction to Ratpack (7) --Guice & Spring
(Dot installation) Introduction to Java8_Impression
Introduction to Design Patterns (Composite)
Introduction to Micronaut 2 ~ Unit test ~
Introduction to JUnit (study memo)
Introduction to Spring Boot ① ~ DI ~
Introduction to design patterns (Flyweight)
[Java] Introduction to lambda expressions
Introduction to Spring Boot ② ~ AOP ~
Introduction to Apache Beam (2) ~ ParDo ~
[Ruby] Introduction to Ruby Error statement
Introduction to EHRbase 2-REST API
Introduction to design patterns Prototype
GitHub Actions Introduction to self-made actions
[Java] Introduction to Stream API
Introduction to Design Patterns (Iterator)
Introduction to Spring Boot Part 1
Introduction to Ratpack (1) --What is Ratpack?
XVim2 introduction memo to Xcode12.3
to_ ○
Introduction to RSpec-Everyday Rails Summary-
Introduction to Design Patterns (Strategy)
[Introduction to rock-paper-scissors games] Java
Introduction to Linux Container / Docker (Part 1)
Introduction to swift practice output Chapter5
[Introduction to Java] About lambda expressions
Introduction to algorithms in java-cumulative sum
[Introduction to Java] About Stream API
Introduction to Functional Programming (Java, Javascript)