[JAVA] Introduction à web3j

web3j est une bibliothèque Java qui peut communiquer avec les clients Ethereum (nœuds) via JSON-RPC. Dans cet article, je présenterai l'utilisation de base de web3j.


Sujet

  1. Connectez-vous au client Ethereum
  2. Communiquez avec le client Ethereum via JSON-RPC
    1. web3_clientVersion
    2. eth_getBlockByNumber
    3. eth_sendTransaction
  3. Introduction de fonctions utiles
  4. Traitement à l'aide du fichier Wallet
  5. Classe de wrapper de contrat
  6. Gérez les événements de manière réactive

Connexion au client Ethereum

Tout d'abord, démarrez le client Ethereum et activez la communication JSON-RPC. Par exemple, démarrez Geth pour activer la communication JSON-RPC via HTTP.

Lorsque vous êtes prêt, utilisez web3j pour vous connecter au client Ethereum.

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

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

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

Communiquez avec le client Ethereum via JSON-RPC

Après vous être connecté avec succès au client Ethereum, communiquons avec JSON-RPC. La communication JSON-RPC avec web3j est très simple.

web3_clientVersion Par exemple, pour appeler la méthode web3_clientVersion de JSON-RPC, écrivez comme suit. (Web3_clientVersion est une méthode pour vérifier la version du client Ethereum)

//Connectez-vous avec le client Ethereum
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));
// JSON-Envoyer une demande RPC et recevoir une réponse
Web3ClientVersion response = web3j.web3ClientVersion().send();
//Résultat de sortie
System.out.println(response.getResult());

production(Exemple)


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

Comme vous pouvez le voir, web3j fournit sa propre méthode Java pour demander chaque méthode JSON-RPC.

eth_getBlockByNumber Voici un exemple où vous devez spécifier un argument de méthode. Ici, utilisons la méthode JSON-RPC ʻeth_getBlockByNumber` pour obtenir les dernières ("dernières") informations de bloc.

//Connectez-vous avec le client Ethereum
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));
// JSON-Envoyer une demande RPC et recevoir une réponse
EthBlock response = web3j.ethGetBlockByNumber(
    DefaultBlockParameterName.LATEST, //numéro de bloc. Voici une balise qui représente le dernier bloc"latest"Spécifier
    false //Si vrai, obtenez les détails de la transaction. Si faux, n'obtient que le hachage de transaction
    ).send();
//Résultat de sortie
Block block = response.getResult();
System.out.println("hash:" + block.getHash());
System.out.println("number:" + block.getNumber());

production(Exemple)


hash:0x7abc74f4b77054a378cd8969b77ca207ed74ff925bd751314186180d37818d33
number:7311

De cette façon, les arguments de méthode peuvent également être spécifiés selon les spécifications JSON-RPC, donc je pense que c'est très facile à comprendre.

eth_sendTransaction Voici un exemple qui implique l'émission d'une transaction. Ici, envoyons Ether en utilisant le JSON-RPC ʻeth_sendTransaction`.

Mais avant cela, vous devez déverrouiller votre compte. Si le client Ethereum est Geth, JSON-RPC fournit une méthode personal_unlockAccount, alors utilisez-la pour déverrouiller votre compte, puis envoyer Ether.

//Connectez-vous avec le client Ethereum
//Admin est une sous-classe de Web3j"personal_unlockAccount"Le traitement de la demande est mis en œuvre.
Admin web3j = Admin.build(new HttpService("http://localhost:8545"));

// "personal_unlockAccount"Envoyez une demande et recevez une réponse
PersonalUnlockAccount unlockAccountResponse = web3j.personalUnlockAccount(
    "0x766a1c4737970feddde6f2b8659fca05bd0339ab", //adresse
    "pass1" //mot de passe
    ).send();

//Si le déverrouillage est réussi, envoyez Ether
if (unlockAccountResponse.getResult()) {
    // "eth_sendTransaction"Créez un objet à passer à l'argument de
    Transaction transaction = Transaction.createEtherTransaction(
        "0x766a1c4737970feddde6f2b8659fca05bd0339ab", // from
        null, //nonce. Non spécifié cette fois, donc nul
        null, //gasPrice. Non spécifié cette fois, donc nul
        null, //Limite de gaz. Non spécifié cette fois, donc nul
        "0x0cbc0fe59d39e58d7369ca436fe5c6b4b71341d5", // to
        BigInteger.valueOf(100) // value
        );
    
    // "eth_sendTransaction"Envoyez une demande et recevez une réponse
    EthSendTransaction sendTransactionResponse = web3j.ethSendTransaction(transaction).send();
    //Résultat de sortie
    System.out.println(sendTransactionResponse.getResult());
}

production(Exemple)


0x3557db13b5ac56f1e3e23ab9eeccd11b2c4daf73e416496d53c5bba377202a61

Introduction de fonctions utiles

web3j offre des fonctionnalités utiles qui vont au-delà du simple appel de méthodes JSON-RPC. Ici, nous allons présenter les trois fonctions suivantes.

--Traitement à l'aide du fichier Wallet

Traitement à l'aide d'un fichier portefeuille

Qu'est-ce qu'un fichier Wallet? Vous pourriez penser cela. C'est ce qu'on appelle un "fichier clé" dans Geth. Le fichier de clé est créé lorsque vous exécutez geth account new. Normalement, dans Geth, le fichier clé est placé dans" \ <datadir > / keystore ". Ce "fichier clé" est appelé "fichier portefeuille" dans web3j.

Dans web3j, le processus lié au déverrouillage du compte est simplifié en utilisant le fichier portefeuille. Ici, envoyons Ether en utilisant le fichier Wallet.

Tout d'abord, placez (copiez) le fichier Wallet dans un emplacement accessible depuis l'environnement dans lequel le programme web3j est exécuté. Lorsque vous êtes prêt, utilisez votre fichier Wallet pour envoyer de l'Ether.

//Connectez-vous avec le client Ethereum
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Charger le fichier de portefeuille
Credentials credentials = WalletUtils.loadCredentials(
    "pass1", //Mot de passe du compte
    "/pass/to/walletfile"
    );

//Envoyer de l'éther
TransactionReceipt receipt = Transfer.sendFunds(
    web3j,
    credentials,
    "0xdc87fc3ac1ec09ed43623dd9da4c6f3d792a88f5", // to
    new BigDecimal("1000"), // value
    Unit.ETHER // unit
    ).send();

Une fois que vous avez chargé le fichier de portefeuille, vous pouvez l'utiliser autant de fois que vous le souhaitez. Si vous souhaitez émettre plusieurs transactions, vous n'avez pas à demander plusieurs fois personal_unlockAccount, ce qui simplifie le processus.

Classe de wrapper de contrat

web3j fournit un outil (outil en ligne de commande) pour générer une classe wrapper pour un contrat. Les classes wrapper facilitent le déploiement de contrats et les méthodes d'appel. (Bien sûr, il est également possible de demander JSON-RPC ʻeth_sendTransaction ou ʻeth_call pour déployer le contrat ou appeler la méthode sans utiliser la classe wrapper.)

Ici, à titre d'exemple, la classe wrapper de la source suivante écrite en Solidity est générée.

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

Commencez par compiler la source en utilisant Online Compiler. Vous pouvez obtenir l'ABI et le bytecode en compilant la source. Enregistrez l'ABI et le code d'octet obtenus dans un fichier.

Dans l'exemple, j'ai enregistré l'ABI et le bytecode dans un fichier comme indiqué ci-dessous.

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

Ensuite, récupérez les outils de ligne de commande. Vous pouvez télécharger les outils de ligne de commande à partir de la page de publication de GitHub (https://github.com/web3j/web3j/releases).

Décompressez le fichier compressé téléchargé et exécutez le fichier exécutable sous le répertoire bin comme suit.

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

Si la commande réussit, une classe wrapper avec le nom "Token.java" sera générée dans le répertoire spécifié par -o et -p.

Maintenant que vous êtes prêt, utilisons la classe wrapper pour déployer le contrat et appeler la méthode.

//Connectez-vous avec le client Ethereum
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Charger le fichier de portefeuille
Credentials credentials = WalletUtils.loadCredentials(
    "pass1", //Mot de passe du compte
    "/pass/to/walletfile"
    );	

//Contrat de déploiement
Token token = Token.deploy(
    web3j,
    credentials,
    BigInteger.valueOf(1000000000L), // gasPrice
    BigInteger.valueOf(4700000L), // gasLimit
    BigInteger.valueOf(100000000000L) //initialSupply (argument du constructeur)
    ).send();

//Sortir l'adresse du contrat
System.out.println("contract address: " + token.getContractAddress());

//Appel de méthode (pas de transaction)
System.out.println("totalSupply: " + token.totalSupply().send());
System.out.println("balance of user1: " + token.balanceOf("0x766a1c4737970feddde6f2b8659fca05bd0339ab").send());

//Appel de méthode (avec transaction)
System.out.println("Sending ether to user2...");
TransactionReceipt tran = token.transfer("0xdc87fc3ac1ec09ed43623dd9da4c6f3d792a88f5", BigInteger.valueOf(1000L)).send();

//Sortie de résultat
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());

production(Exemple)


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

Vous pouvez voir que le déploiement du contrat et l'appel de méthode peuvent être décrits très simplement.

Gérez les événements de manière réactive

Enfin, je présenterai la fonction de surveillance des événements. web3j fournit une fonction pour traiter les événements Ethereum de manière réactive.

La surveillance d'événements à l'aide de JSON-RPC consiste généralement à enregistrer d'abord un filtre en utilisant ʻeth_newBlockFilter, ʻeth_newFilter, etc., puis à interroger l'événement en utilisant ʻeth_getFilterChanges`. .. C'est très gênant, n'est-ce pas?

En utilisant la fonction fournie par web3j, la surveillance des événements peut être décrite comme suit.

//Connectez-vous avec le client Ethereum
Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Enregistrer le filtre (démarrer la surveillance des événements)
Disposable disposable = web3j.blockFlowable(false).subscribe(ethBlock -> {
    //Lorsqu'un nouveau bloc se produit, effectuez le traitement suivant
    Block block = ethBlock.getBlock();
    System.out.println(block.getNumber());
});

//Supprimer le filtre (fin de la surveillance des événements)
disposable.dispose();

C'est très simple à écrire.

Recommended Posts

Introduction à web3j
Introduction à Ruby 2
Introduction à Micronaut 1 ~ Introduction ~
[Java] Introduction à Java
Introduction à la migration
Introduction à Java
Introduction à Doma
Introduction aux fichiers JAR
Introduction à Ratpack (8) - Session
Introduction à l'arithmétique des bits
Introduction à Ratpack (6) - Promesse
Introduction à Ratpack (9) --Thymeleaf
Introduction à PlayFramework 2.7 ① Présentation
Introduction à la mise en page Android
Introduction aux modèles de conception (introduction)
Introduction à la programmation pratique
Introduction à la commande javadoc
Introduction à la commande jar
Introduction à Ratpack (2) -Architecture
Introduction au style lambda
Introduction à la commande java
Introduction au développement de Keycloak
Introduction à la commande javac
Introduction aux modèles de conception (Builder)
Introduction à Ratpack (5) --Json & Registry
Introduction à la métabase ~ Construction de l'environnement ~
Introduction à Ratpack (7) --Guice & Spring
(Installation par points) Introduction à Java8_Impression
Introduction aux modèles de conception (composite)
Introduction à Micronaut 2 ~ Test unitaire ~
Introduction à JUnit (note d'étude)
Introduction à Spring Boot ① ~ DI ~
Introduction aux modèles de conception (poids mouche)
[Java] Introduction à l'expression lambda
Introduction à Spring Boot ② ~ AOP ~
Introduction à Apache Beam (2) ~ ParDo ~
Introduction à l'API EHRbase 2-REST
Introduction au prototype de modèles de conception
[Java] Introduction à l'API Stream
Introduction aux modèles de conception (Iterator)
Introduction à Spring Boot, partie 1
Introduction à Ratpack (1) - Qu'est-ce que Ratpack?
à_ ○
Introduction aux modèles de conception (stratégie)
[Introduction aux jeux Janken (comme)] Java
Introduction à Linux Container / Docker (Partie 1)
Introduction à la pratique rapide Chapitre 5
[Introduction à Java] À propos des expressions lambda
Introduction aux algorithmes avec somme cumulée Java
[Introduction à Java] À propos de l'API Stream
Introduction à la programmation fonctionnelle (Java, Javascript)