a
a
Weather:
city not found
HomeBitcoinGérez un compte Ethereum avec Java et Web3j

Gérez un compte Ethereum avec Java et Web3j

Autres articles de cette série:


La blockchain Ethereum est souvent comparée à un World Computer avec un statut mondial. Le statut global grandit à chaque nouveau bloc et comprend de nombreux comptes organisés dans une arborescence Merkle.

Chaque compte a un état composé d’informations telles que balance, nonce, storageRoot et codeHash et est identifié par une adresse de 20 octets (par exemple: 0x66aac71c0c81ec00aebead84914a10e307a4cbf9).

Il existe deux types de comptes:

  • Compte externe, qui sont contrôlés par des clés privées et n’ont pas de code associé.
  • Comptes contractuels, qui sont contrôlés par le code de contrat respectif et auquel un code est associé.

Dans ce didacticiel, nous nous concentrons sur les comptes détenus en externe et sur la manière de récupérer des informations telles qu’un solde, de créer ou d’ouvrir un compte et d’envoyer des transactions à un autre compte à l’aide de la bibliothèque Java Web3j.

1. Récupérer des informations publiques sur un compte

La blockchain Ethereum est un registre public partagé que nous pouvons interroger pour récupérer des informations d’état à un moment différent, ou un numéro de bloc.

Obtenez le solde de votre compte

Chaque compte a un solde de crypto-monnaie native d’Ethereum appelé Éther. En utilisant notre instance Web3j (voir article-1), il est possible de récupérer le solde d’un compte dans un bloc donné en utilisant la fonction web3.ethGetBalance(<accountAddress>, <blockNo>).send()

Le solde est stocké par défaut dans la plus petite dénomination d’éther appelée wei (1 éther = 10 ^ 18 wei) mais Web3j fournit une classe utilitaire pratique Convert pour convertir des valeurs entre différentes unités.

  • Récupérez le dernier solde (dernier blocage) d’un compte:
EthGetBalance balanceWei = web3.ethGetBalance("0xF0f15Cedc719B5A55470877B0710d5c7816916b1", DefaultBlockParameterName.LATEST).send();
System.out.println("balance in wei: " + balanceWei);

BigDecimal balanceInEther = Convert.fromWei(balanceWei.getBalance().toString(), Unit.ETHER);
System.out.println("balance in ether: " + balanceInEther);

Dans l’exemple ci-dessus, le dernier solde du compte 0xF0f15Cedc719B5A55470877B0710d5c7816916b1 est 33,25 éther.

  • Récupérez le solde d’un compte dans un bloc spécifique, si la blockchain à laquelle vous vous connectez a généré des blocs jusqu’à présent. Les chaînes de test peuvent ne pas encore avoir:
EthGetBalance balance = web3.ethGetBalance("0xF0f15Cedc719B5A55470877B0710d5c7816916b1", new DefaultBlockParameterNumber(3000000)).send();

BigDecimal balanceInEther = Convert.fromWei(balance.getBalance().toString(), Unit.ETHER);

Le solde du bloc no. 3.000.000 du compte 0xF0f15Cedc719B5A55470877B0710d5c7816916b1 est 8.12 éthers.

Obtenez le compte nonce

Le fichier est également inclus dans le statut d’un compte il n’y a, un numéro de séquence qui symbolise le nombre de transactions effectuées par un compte.

Web3j fournit la méthode web3.ethGetTransactionCount(<accountAddress>, <blockNo>).send() pour récupérer le nonce à un numéro de bloc donné, dans ce cas le bloc le plus récent.

EthGetTransactionCount ethGetTransactionCount = web3.ethGetTransactionCount("0xF0f15Cedc719B5A55470877B0710d5c7816916b1", DefaultBlockParameterName.LATEST).send();

BigInteger nonce =  ethGetTransactionCount.getTransactionCount();

2. Ouvrez ou créez un compte

Pour vérifier un compte de propriété externe et le fonds qui y est alloué, les 32 octets Clé privée associé à un compte est obligatoire. Une clé privée est une information confidentielle, elle n’est donc généralement pas fournie en texte clair tel que 3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266 mais il est protégé et crypté dans un portefeuille. Il existe de nombreuses formes de portefeuilles (plus ou moins sûrs et pratiques):

Dans cette section, nous allons apprendre comment télécharger un portefeuille existant et en créer un nouveau avec Web3j pour instancier un fichier Credentials objet que nous pouvons utiliser pour signer et envoyer en toute sécurité des transactions sur la blockchain Ethereum.

Télécharger un portefeuille

À partir d’un keystore chiffré JSON

La première forme de portefeuille est le fichier de clés chiffré JSON, qui est une version chiffrée par mot de passe de la clé privée. C’est le moyen le plus standard utilisé par des clients comme Pantheon ou Geth, mais aussi par des outils en ligne comme MyEtherWallet pour protéger une clé privée des attaquants potentiels.

Web3j fournit une classe utilitaire appelée WalletUtils pour télécharger un portefeuille dans un fichier Credentials object (wrapper contenant l’adresse du compte et la paire de clés).

String walletPassword = "secr3t";
String walletDirectory = "/path/to/wallets";
String walletName = "UTC--2019-06-20T08-55-56.200000000Z--fd7d68e16ef61868f3e325fafdf2fc1ec0b77649.json";

// Load the JSON encryted wallet
Credentials credentials = WalletUtils.loadCredentials(walletPassword, walletDirectory + "/" + walletName);

// Get the account address
String accountAddress = credentials.getAddress();

// Get the unencrypted private key into hexadecimal
String privateKey = credentials.getEcKeyPair().getPrivateKey().toString(16);

À partir d’une phrase mnémotechnique

Une autre forme courante de clé privée est le fichier Phrase mnémonique (ou phrase de départ) qui convertit la clé de 32 octets en un groupe de 12 mots faciles à retenir. Par exemple: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat. Ce module a été mis en place par Bitcoin avec la proposition BIP39.

Un mnémonique vérifie plusieurs clés privées grâce à un mécanisme pour dériver de manière déterministe le mnémonique d’un chemin.

En option, nous pouvons crypter le mnémonique avec un mot de passe.

String password = null; // no encryption
String mnemonic = "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat";

Credentials credentials = WalletUtils.loadBip39Credentials(password, mnemonic);

Par défaut, Web3j utilise un chemin de dérivation égal à m/44'/60'/0'/1 (lisez cet article pour comprendre chemin de dérivation). Cependant, vous pouvez ouvrir un autre compte sur un chemin différent:

String password = null; // no encryption
String mnemonic = "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat";

//Derivation path wanted: // m/44'/60'/0'/0
int[] derivationPath = {44 | Bip32ECKeyPair.HARDENED_BIT, 60 | Bip32ECKeyPair.HARDENED_BIT, 0 | Bip32ECKeyPair.HARDENED_BIT, 0,0};

// Generate a BIP32 master keypair from the mnemonic phrase
Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(MnemonicUtils.generateSeed(mnemonic, password));

// Derived the key using the derivation path
Bip32ECKeyPair  derivedKeyPair = Bip32ECKeyPair.deriveKeyPair(masterKeypair, derivationPath);

// Load the wallet for the derived key
Credentials credentials = Credentials.create(derivedKeyPair);

À partir d’une clé privée

Comme mentionné ci-dessus, une clé privée est un nombre de 32 octets. Pour analyser une clé privée avec Web3j, nous devons passer la clé privée à la classe Credentials.

String pk = "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3";

Credentials credentials = Credentials.create(pk);

Créer un portefeuille

Enfin, si nous n’avons pas encore de compte et que nous voulons en créer un nouveau à partir de zéro. Web3j WalletUtils propose une méthode pour créer un keystore chiffré JSON.

String walletPassword = "secr3t";
String walletDirectory = "/path/to/destination/";

String walletName = WalletUtils.generateNewWalletFile(walletPassword, new File(walletDirectory));
System.out.println("wallet location: " + walletDirectory + "/" + walletName);


Credentials credentials = WalletUtils.loadCredentials(walletPassword, walletDirectory + "/" + walletName);

String accountAddress = credentials.getAddress();
System.out.println("Account address: " + credentials.getAddress());

3. Soumettez une transaction

Maintenant que nous avons appris à récupérer des informations publiques (d’état), telles que le solde d’un compte et comment ouvrir un compte en utilisant différentes méthodes, nous pouvons envoyer une transaction vers un autre compte.

Une transaction sur la blockchain Ethereum comprend les informations suivantes:

  • il n’y a: un décompte du nombre de transactions envoyées par l’expéditeur.
  • gasPrix (en wei): le montant que l’expéditeur est prêt à payer par unité de gaz nécessaire pour exécuter la transaction.
  • gasLimit: la quantité maximale de gaz que l’expéditeur est prêt à payer pour effectuer cette transaction.
  • pour: L’adresse du compte du destinataire.
  • valeur (en wei): la quantité de Wei à transférer de l’expéditeur au destinataire. Dans une transaction de création de contrat, cette valeur sert de solde d’ouverture dans le compte de contrat nouvellement créé.
  • Signature: Signature cryptographique identifiant l’expéditeur de la transaction (de).
  • Les données: Champ facultatif utilisé pour communiquer avec un contrat intelligent (chaîne codée comprenant le nom de la fonction et les paramètres).

Il existe deux façons d’envoyer une transaction à la blockchain:

  • Via le nœud Ethereum:
    Cela implique l’envoi d’une transaction non signée au client Ethereum propriétaire du compte déverrouillé.
    Personnellement, je ne recommande pas cette méthode qui pourrait mettre votre compte en danger si le nœud Ethereum n’est pas correctement sécurisé

  • Transaction hors ligne:
    Le concept est de créer d’abord l’objet de transaction rawTransaction et signez-le avec une clé privée (identifiant Web3j). Deuxièmement, envoyez-le au nœud Ethereum via l’API JSON-RPC pour le propager sur le réseau.

Une fois qu’une transaction est transmise au réseau, un hachage de la transaction est retourné au client mais la transaction n’est pas encore exécutée. Un ensemble de mineurs / validateurs présents sur le réseau collecte toutes les transactions en cours, les regroupe dans le bloc suivant et valide leur validité. Une fois vérifiée, la transaction est tirée dans le nouveau bloc. À ce stade, le client peut demander un reçu de transaction haché pour accuser la réussite de l’exécution de sa transaction.

Envoyer des fonds d’un compte à un autre

1. Téléchargez un compte et obtenez le nonce

Comme expliqué dans les sections précédentes, nous devons charger un compte à partir de l’une des méthodes et récupérer la valeur nonce de ce compte:

String walletPassword = "secr3t";
String walletPath = "/path/to/wallet/UTC--2019-06-20T11-41-39.478000000Z--256c75c85f9c27ac5b2a22f085d9643f7ed91dc1.json";

// Decrypt and open the wallet into a Credential object
Credentials credentials = WalletUtils.loadCredentials(walletPassword, walletPath);

// Get nonce
EthGetTransactionCount ethGetTransactionCount = web3.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.LATEST).send();
BigInteger nonce =  ethGetTransactionCount.getTransactionCount();
2. Configurez le compte du destinataire et le montant à envoyer

Dans l’étape suivante, nous configurons le montant (en Wei) à envoyer à un compte destinataire.

// Recipient account
String recipientAddress = "0xDD6325C45aE6fAbD028D19fa1539663Df14813a8";

// Value to Transfer
BigInteger value = Convert.toWei("1", Unit.ETHER).toBigInteger();
3. Configurer les paramètres du gaz

Le gaz représente les frais de réseau prélevés par le mineur qui extrait le bloc qui comprend votre transaction.

Lors de la soumission d’une transaction, deux paramètres sont importants:

  • Limite de gaz (en unités): La limite de gaz fait référence à la quantité maximale de gaz que vous êtes prêt à dépenser pour une transaction donnée. Une fois la transaction exécutée, si trop de gaz (gasLimit) a été envoyé, le gaz résiduel est remboursé à l’expéditeur.

  • Prix ​​du gaz (en wei): Quantité d’éther que vous êtes prêt à payer pour chaque unité de gaz

// A transfer cost 21,000 units of gas
BigInteger gasLimit = BigInteger.valueOf(21000);

// I am willing to pay 1Gwei (1,000,000,000 wei or 0.000000001 ether) for each unit of gas consumed by the transaction.
BigInteger gasPrice = Convert.toWei("1", Unit.GWEI).toBigInteger();
4. Préparez la transaction brute

Une transaction brute pour un transfert de fonds contient tous les champs de données de transaction sauf:

  • Les données: pas une transaction de contrat intelligent
  • Signature: signature non encore signée
// Prepare the rawTransaction
RawTransaction rawTransaction  = RawTransaction.createEtherTransaction(
    nonce,
    gasPrice,
    gasLimit,
    recipientAddress,
    value);
5. Signature

La partie signature nécessite l’extension rawTransaction aussi bien que credentials (keypair) utilisé pour signer cryptographiquement la transaction.

// Sign the transaction
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);

// Convert it to Hexadecimal String to be sent to the node
String hexValue = Numeric.toHexString(signedMessage);
6. Envoyer au nœud via JSON-RPC

La dernière étape consiste à envoyer la transaction signée au nœud afin qu’elle puisse être vérifiée et transmise au réseau. En cas de succès, la méthode renvoie une réponse constituée du hachage de la transaction.

// Send transaction
EthSendTransaction ethSendTransaction = web3.ethSendRawTransaction(hexValue).send();

// Get the transaction hash
String transactionHash = ethSendTransaction.getTransactionHash();
7. Attendez que la transaction soit minée.

Comme expliqué ci-dessus, lorsque la transaction signée est propagée sur le réseau, en fonction de nombreux facteurs (prix du gaz, congestion du réseau), cela peut prendre un certain temps pour voir la transaction extraite et ajoutée au dernier bloc.

C’est pourquoi le code suivant consiste en une simple boucle pour vérifier toutes les 3 secondes si la transaction est extraite en appelant la méthode web3.ethGetTransactionReceipt(<txhash>).send().

// Wait for transaction to be mined
Optional<TransactionReceipt> transactionReceipt = null;
do {
  EthGetTransactionReceipt ethGetTransactionReceiptResp = web3.ethGetTransactionReceipt(transactionHash).send();
  transactionReceipt = ethGetTransactionReceiptResp.getTransactionReceipt();

  Thread.sleep(3000); // Retry after 3 sec
} while(!transactionReceipt.isPresent());
Résultat

Voici la version complète du code qui comprend tout ce qui a été expliqué dans cet article:

// Transaction.java
package io.kauri.tutorials.java_ethereum;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Optional;

import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Convert;
import org.web3j.utils.Convert.Unit;
import org.web3j.utils.Numeric;

public class Transaction {

  public static void main(String[] args)  {

    System.out.println("Connecting to Ethereum ...");
    Web3j web3 = Web3j.build(new HttpService("https://rinkeby.infura.io/v3/083836b2784f48e19e03487eb3209923"));
    System.out.println("Successfuly connected to Ethereum");

    try {
      String pk = "CHANGE_ME"; // Add a private key here

      // Decrypt and open the wallet into a Credential object
      Credentials credentials = Credentials.create(pk);
      System.out.println("Account address: " + credentials.getAddress());
      System.out.println("Balance: " + Convert.fromWei(web3.ethGetBalance(credentials.getAddress(), DefaultBlockParameterName.LATEST).send().getBalance().toString(), Unit.ETHER));

      // Get the latest nonce
      EthGetTransactionCount ethGetTransactionCount = web3.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.LATEST).send();
      BigInteger nonce =  ethGetTransactionCount.getTransactionCount();

      // Recipient address
      String recipientAddress = "0xAA6325C45aE6fAbD028D19fa1539663Df14813a8";

      // Value to transfer (in wei)
      BigInteger value = Convert.toWei("1", Unit.ETHER).toBigInteger();

      // Gas Parameters
      BigInteger gasLimit = BigInteger.valueOf(21000);
      BigInteger gasPrice = Convert.toWei("1", Unit.GWEI).toBigInteger();

      // Prepare the rawTransaction
      RawTransaction rawTransaction  = RawTransaction.createEtherTransaction(
                 nonce,
                 gasPrice,
                 gasLimit,
                 recipientAddress,
                 value);

      // Sign the transaction
      byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
      String hexValue = Numeric.toHexString(signedMessage);

      // Send transaction
      EthSendTransaction ethSendTransaction = web3.ethSendRawTransaction(hexValue).send();
      String transactionHash = ethSendTransaction.getTransactionHash();
      System.out.println("transactionHash: " + transactionHash);

      // Wait for transaction to be mined
      Optional<TransactionReceipt> transactionReceipt = null;
      do {
        System.out.println("checking if transaction " + transactionHash + " is mined....");
            EthGetTransactionReceipt ethGetTransactionReceiptResp = web3.ethGetTransactionReceipt(transactionHash).send();
            transactionReceipt = ethGetTransactionReceiptResp.getTransactionReceipt();
            Thread.sleep(3000); // Wait 3 sec
      } while(!transactionReceipt.isPresent());

      System.out.println("Transaction " + transactionHash + " was mined in block # " + transactionReceipt.get().getBlockNumber());
      System.out.println("Balance: " + Convert.fromWei(web3.ethGetBalance(credentials.getAddress(), DefaultBlockParameterName.LATEST).send().getBalance().toString(), Unit.ETHER));


    } catch (IOException | InterruptedException ex) {
      throw new RuntimeException(ex);
    }
  }
}

Maintenant que nous comprenons les bases de l’envoi de transactions avec Web3j, je peux vous dire un secret. Web3j fournit une classe utilitaire appelée « Transfer » qui s’occupe de tout (nonce, gaz, interrogation des reçus de transaction, etc.) en une seule ligne de code.

TransactionReceipt receipt = Transfer.sendFunds(web3, credentials, recipientAddress, BigDecimal.valueOf(1), Unit.ETHER).send();

Sommaire

Dans cet article, nous avons appris qu’Ethereum Global State consiste en un mappage de tous les états de compte. Nous pouvons interroger chaque statut de compte qui peut être interrogé pour des informations telles que le solde et le nonce.

Un compte est contrôlé par la personne qui détient la clé privée de ce compte. La clé privée peut prendre plusieurs formes et est généralement protégée dans un portefeuille. Web3j vous permet d’ouvrir un portefeuille à partir d’un fichier crypté JSON, d’une phrase mnémotechnique ou directement à partir de la clé privée.

Pour envoyer une transaction entre deux comptes, Web3j peut générer un objet de transaction, le signer et le propager sur le réseau pour interroger la Blockchain afin d’obtenir le reçu de la transaction lors de son extraction.

Ressources

Prochaines étapes:
– Générer un wrapper Java à partir de votre contrat intelligent – Interaction avec un contrat intelligent Ethereum en Java – Écoute des événements du contrat intelligent Ethereum en Java – Utilisation de Pantheon, le client Java Ethereum avec Linux


  • Titre original Kauri: Gérez un compte Ethereum avec Java et Web3j
  • Lien Kauri original: https://kauri.io/manage-an-ethereum-account-with-java-and-web3j/925d923e12c543da9a0a3e617be963b4/a
  • Auteur original Kauri: Grégory Jeanmart (@gregjeanmart)
  • Date de sortie d’origine de Kauri: 2020-05-01
  • Balises originales de Kauri: ethereum, java, solde, web3j, compte
  • Hash original de Kauri: QmevjY4PmnL2qAc4W6Ev7gWWiPYri4hn2FjXn2AYPoaM62
  • Point de contrôle d’origine de Kauri: QmZUeDv5bCt7vrRCQbwPMQf812VWip98dcsMJHdYdaiQ3d

https://kauri.io/communities/Java%20Ethereum/manage-an-ethereum-account-with-java-and-web3j/

No comments

leave a comment