[JAVA] Einführung in web3j

web3j ist eine Java-Bibliothek, die über JSON-RPC mit Ethereum-Clients (Knoten) kommunizieren kann. In diesem Artikel werde ich die grundlegende Verwendung von web3j vorstellen.


Thema

  1. Stellen Sie eine Verbindung zum Ethereum-Client her
  2. Kommunizieren Sie mit dem Ethereum-Client über JSON-RPC
    1. web3_clientVersion
    2. eth_getBlockByNumber
    3. eth_sendTransaction
  3. Einführung nützlicher Funktionen
  4. Verarbeitung mit Wallet-Datei
  5. Vertragsverpackungsklasse
  6. Behandeln Sie Ereignisse reaktiv

Verbindung zum Ethereum-Client herstellen

Starten Sie zunächst den Ethereum-Client und aktivieren Sie die JSON-RPC-Kommunikation. Starten Sie beispielsweise "Geth", um die JSON-RPC-Kommunikation über HTTP zu aktivieren.

Wenn Sie bereit sind, verwenden Sie web3j, um eine Verbindung zum Ethereum-Client herzustellen.

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

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

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

Kommunizieren Sie mit dem Ethereum-Client über JSON-RPC

Nachdem Sie erfolgreich eine Verbindung zum Ethereum-Client hergestellt haben, können Sie mit JSON-RPC kommunizieren. Die JSON-RPC-Kommunikation mit web3j ist sehr einfach.

web3_clientVersion Um beispielsweise die Methode "web3_clientVersion" von JSON-RPC aufzurufen, schreiben Sie wie folgt. (Web3_clientVersion ist eine Methode zum Überprüfen der Version des Ethereum-Clients)

//Stellen Sie eine Verbindung mit dem Ethereum-Client her
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));
// JSON-RPC-Anfrage senden und Antwort empfangen
Web3ClientVersion response = web3j.web3ClientVersion().send();
//Ausgabeergebnis
System.out.println(response.getResult());

Ausgabe(Beispiel)


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

Wie Sie sehen können, bietet web3j eine eigene Java-Methode zum Anfordern jeder JSON-RPC-Methode.

eth_getBlockByNumber Im Folgenden finden Sie ein Beispiel, in dem Sie ein Methodenargument angeben müssen. Hier erhalten Sie die neuesten ("neuesten") Blockinformationen mithilfe der JSON-RPC-Methode "eth_getBlockByNumber".

//Stellen Sie eine Verbindung mit dem Ethereum-Client her
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));
// JSON-RPC-Anfrage senden und Antwort empfangen
EthBlock response = web3j.ethGetBlockByNumber(
    DefaultBlockParameterName.LATEST, //Blocknummer. Hier ist ein Tag, das den neuesten Block darstellt"latest"Konkretisieren
    false //Wenn dies der Fall ist, erhalten Sie die Transaktionsdetails. Wenn false, erhalten Sie nur den Transaktions-Hash
    ).send();
//Ausgabeergebnis
Block block = response.getResult();
System.out.println("hash:" + block.getHash());
System.out.println("number:" + block.getNumber());

Ausgabe(Beispiel)


hash:0x7abc74f4b77054a378cd8969b77ca207ed74ff925bd751314186180d37818d33
number:7311

Auf diese Weise können Methodenargumente auch gemäß den JSON-RPC-Spezifikationen angegeben werden, sodass ich denke, dass dies sehr einfach zu verstehen ist.

eth_sendTransaction Das folgende Beispiel beinhaltet die Ausgabe einer Transaktion. Hier senden wir Ether mit dem JSON-RPC eth_sendTransaction.

Zuvor müssen Sie jedoch Ihr Konto entsperren. Wenn der Ethereum-Client "Geth" ist, bietet JSON-RPC eine "personal_unlockAccount" -Methode. Verwenden Sie diese Methode, um Ihr Konto zu entsperren und dann Ether zu senden.

//Stellen Sie eine Verbindung mit dem Ethereum-Client her
//Admin ist eine Unterklasse von Web3j"personal_unlockAccount"Die Anforderungsverarbeitung ist implementiert.
Admin web3j = Admin.build(new HttpService("http://localhost:8545"));

// "personal_unlockAccount"Senden Sie eine Anfrage und erhalten Sie eine Antwort
PersonalUnlockAccount unlockAccountResponse = web3j.personalUnlockAccount(
    "0x766a1c4737970feddde6f2b8659fca05bd0339ab", //Adresse
    "pass1" //Passwort
    ).send();

//Wenn das Entsperren erfolgreich ist, senden Sie Ether
if (unlockAccountResponse.getResult()) {
    // "eth_sendTransaction"Erstellen Sie ein Objekt, das an das Argument von übergeben werden soll
    Transaction transaction = Transaction.createEtherTransaction(
        "0x766a1c4737970feddde6f2b8659fca05bd0339ab", // from
        null, //nonce. Diesmal nicht angegeben, also null
        null, //gasPreis. Diesmal nicht angegeben, also null
        null, //Gaslimit. Diesmal nicht angegeben, also null
        "0x0cbc0fe59d39e58d7369ca436fe5c6b4b71341d5", // to
        BigInteger.valueOf(100) // value
        );
    
    // "eth_sendTransaction"Senden Sie eine Anfrage und erhalten Sie eine Antwort
    EthSendTransaction sendTransactionResponse = web3j.ethSendTransaction(transaction).send();
    //Ausgabeergebnis
    System.out.println(sendTransactionResponse.getResult());
}

Ausgabe(Beispiel)


0x3557db13b5ac56f1e3e23ab9eeccd11b2c4daf73e416496d53c5bba377202a61

Einführung nützlicher Funktionen

web3j bietet nützliche Funktionen, die über das einfache Aufrufen von JSON-RPC-Methoden hinausgehen. Hier werden die folgenden drei Funktionen vorgestellt.

Verarbeitung mit einer Wallet-Datei

Was ist eine Wallet-Datei? Das könnte man denken. Dies wird in "Geth" als "Schlüsseldatei" bezeichnet. Die Schlüsseldatei wird erstellt, wenn Sie "geth account new" ausführen. Normalerweise wird die Schlüsseldatei in "Geth" in "\ <datadir > / keystore" abgelegt. Diese "Schlüsseldatei" wird in web3j als "Brieftaschendatei" bezeichnet.

In web3j wird der Vorgang zum Entsperren des Kontos mithilfe der Brieftaschendatei vereinfacht. Hier senden wir Ether mithilfe der Wallet-Datei.

Platzieren (kopieren) Sie zunächst die Wallet-Datei an einem Ort, auf den von der Umgebung aus zugegriffen werden kann, in der das web3j-Programm ausgeführt wird. Wenn Sie bereit sind, verwenden Sie Ihre Wallet-Datei, um Ether zu senden.

//Stellen Sie eine Verbindung mit dem Ethereum-Client her
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Brieftaschendatei laden
Credentials credentials = WalletUtils.loadCredentials(
    "pass1", //Konto Passwort
    "/pass/to/walletfile"
    );

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

Sobald Sie die Brieftaschendatei geladen haben, können Sie sie beliebig oft verwenden. Wenn Sie mehrere Transaktionen ausführen möchten, müssen Sie "personal_unlockAccount" nicht mehrmals anfordern, was den Vorgang vereinfacht.

Vertragsverpackungsklasse

web3j bietet ein Tool (Befehlszeilentool) zum Generieren einer Wrapper-Klasse für einen Vertrag. Wrapper-Klassen vereinfachen die Bereitstellung von Verträgen und Aufrufmethoden. (Natürlich ist es auch möglich, die JSON-RPC eth_sendTransaction und eth_call anzufordern, den Vertrag bereitzustellen und die Methode aufzurufen, ohne die Wrapper-Klasse zu verwenden.)

Hier wird als Beispiel die Wrapper-Klasse der folgenden in Solidity geschriebenen Quelle generiert.

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;
    }
}

Kompilieren Sie zunächst die Quelle mit Online Compiler. Sie können den ABI und den Bytecode erhalten, indem Sie die Quelle kompilieren. Speichern Sie den erhaltenen ABI- und Bytecode in einer Datei.

Im Beispiel habe ich den ABI und den Bytecode wie unten gezeigt in einer Datei gespeichert.

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

Als nächstes erhalten Sie die Befehlszeilen-Tools. Sie können die Befehlszeilentools von der GitHub-Release-Seite (https://github.com/web3j/web3j/releases) herunterladen.

Entpacken Sie die heruntergeladene komprimierte Datei und führen Sie die ausführbare Datei im bin-Verzeichnis wie folgt aus.

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

Wenn der Befehl erfolgreich ist, wird eine Wrapper-Klasse mit dem Namen "Token.java" in dem durch -o und -p angegebenen Verzeichnis generiert.

Nachdem Sie fertig sind, verwenden wir die Wrapper-Klasse, um den Vertrag bereitzustellen und die Methode aufzurufen.

//Stellen Sie eine Verbindung mit dem Ethereum-Client her
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Brieftaschendatei laden
Credentials credentials = WalletUtils.loadCredentials(
    "pass1", //Konto Passwort
    "/pass/to/walletfile"
    );	

//Vertrag bereitstellen
Token token = Token.deploy(
    web3j,
    credentials,
    BigInteger.valueOf(1000000000L), // gasPrice
    BigInteger.valueOf(4700000L), // gasLimit
    BigInteger.valueOf(100000000000L) //initialSupply (Konstruktorargument)
    ).send();

//Geben Sie die Adresse des Vertrags aus
System.out.println("contract address: " + token.getContractAddress());

//Methodenaufruf (keine Transaktion)
System.out.println("totalSupply: " + token.totalSupply().send());
System.out.println("balance of user1: " + token.balanceOf("0x766a1c4737970feddde6f2b8659fca05bd0339ab").send());

//Methodenaufruf (mit Transaktion)
System.out.println("Sending ether to user2...");
TransactionReceipt tran = token.transfer("0xdc87fc3ac1ec09ed43623dd9da4c6f3d792a88f5", BigInteger.valueOf(1000L)).send();

//Ergebnisausgabe
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());

Ausgabe(Beispiel)


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

Sie sehen, dass die Vertragsbereitstellung und der Methodenaufruf sehr einfach beschrieben werden können.

Ereignisse reaktiv behandeln

Abschließend werde ich die Ereignisüberwachungsfunktion vorstellen. web3j bietet eine Funktion zum reaktiven Verarbeiten von Ethereum-Ereignissen.

Bei der Ereignisüberwachung mit JSON-RPC wird normalerweise zuerst ein Filter mit "eth_newBlockFilter", "eth_newFilter" usw. registriert und anschließend das Ereignis mit "eth_getFilterChanges" abgefragt. .. Das ist sehr mühsam, nicht wahr?

Mit der von web3j bereitgestellten Funktion kann die Ereignisüberwachung wie folgt beschrieben werden.

//Stellen Sie eine Verbindung mit dem Ethereum-Client her
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Filter registrieren (Ereignisüberwachung starten)
Disposable disposable = web3j.blockFlowable(false).subscribe(ethBlock -> {
    //Wenn ein neuer Block auftritt, führen Sie die folgende Verarbeitung durch
    Block block = ethBlock.getBlock();
    System.out.println(block.getNumber());
});

//Filter entfernen (Endereignisüberwachung)
disposable.dispose();

Es ist sehr einfach zu schreiben.

Recommended Posts

Einführung in web3j
Einführung in Ruby 2
Einführung in Micronaut 1 ~ Einführung ~
[Java] Einführung in Java
Einführung in die Migration
Einführung in Java
Einführung in Doma
Einführung in JAR-Dateien
Einführung in Ratpack (8) -Session
Einführung in die Bitarithmetik
Einführung in Ratpack (6) --Promise
Einführung in Ratpack (9) - Thymeleaf
Einführung in PlayFramework 2.7 ① Übersicht
Einführung in das Android-Layout
Einführung in Entwurfsmuster (Einführung)
Einführung in die praktische Programmierung
Einführung in den Befehl javadoc
Einführung in den Befehl jar
Einführung in Ratpack (2) -Architektur
Einführung in den Lambda-Stil
Einführung in den Java-Befehl
Einführung in die Keycloak-Entwicklung
Einführung in den Befehl javac
Einführung in Entwurfsmuster (Builder)
Einführung in Ratpack (5) --Json & Registry
Einführung in Metabase ~ Umgebungskonstruktion ~
Einführung in Ratpack (7) - Guice & Spring
(Punktinstallation) Einführung in Java8_Impression
Einführung in Entwurfsmuster (Composite)
Einführung in Micronaut 2 ~ Unit Test ~
Einführung in JUnit (Studiennotiz)
Einführung in Spring Boot ~ ~ DI ~
Einführung in Designmuster (Fliegengewicht)
[Java] Einführung in den Lambda-Ausdruck
Einführung in Spring Boot ② ~ AOP ~
Einführung in Apache Beam (2) ~ ParDo ~
Einführung in die EHRbase 2-REST-API
Einführung in Entwurfsmuster Prototyp
[Java] Einführung in die Stream-API
Einführung in Entwurfsmuster (Iterator)
Einführung in Spring Boot Teil 1
Einführung in Ratpack (1) - Was ist Ratpack?
to_ ○
Einführung in Entwurfsmuster (Strategie)
[Einführung in Janken (ähnliche) Spiele] Java
Einführung in Linux Container / Docker (Teil 1)
Einführung in die schnelle Übungsausgabe Kapitel 5
[Einführung in Java] Über Lambda-Ausdrücke
Einführung in Algorithmen mit Java-kumulativer Summe
[Einführung in Java] Informationen zur Stream-API
Einführung in die funktionale Programmierung (Java, Javascript)