Es muss ja nicht immer remix sein, um ein Smart-Contract zu compilieren. Es geht auch wie oben dargestellt mit einem Maven-Plugin (oder Gradle) um mit Ethereum-Netzwerk zu interagieren. Also wie können Solidity Smart Contracts kompiliert und dafür eine Java-Wrapper-Klassen dafür generiert werden?
Wir nehmen als Beispiel mein bekannter Smart-Contract Gehirn.sol der den IQ auf der Blockchain festhalten kann und mit Solidity programmiert ist und speichern in in dem src/main/resources Verzeichnis.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @title Gehirn von Thomas Wenzlaff * @dev Mein Smart Contract mit solidity zum Speichern von IQ auf der Blockchain */ contract Gehirn { uint256 iq; constructor() public { // Mittelwert des IQ setzen iq = 100; } function setIQ(uint256 neuerIQ) public payable { iq = neuerIQ; } function getIQ() public view returns (uint256) { return iq; } function getBedeutung() public view returns (string memory) { if (iq <= 40) return "Keine Aussagekraft"; if (iq >= 41 && iq <= 70) return "Weit unterdurchschnittlich – Geistige Behinderung"; if (iq >= 71 && iq <= 79) return "unterdurchschnittlich"; if (iq >= 80 && iq <= 89) return "etwas unterdurchschnittlich"; if (iq >= 90 && iq <=109) return "Durchschnitt"; if (iq >= 110 && iq <=119) return "hoch"; if (iq >= 120 && iq <= 129) return "sehr hoch"; if (iq >= 130 && iq <= 159) return "hochbegabt"; if (iq > 160) return "Keine Aussagekraft"; } } |
Das Plugin wird mit mvn web3j:generate-sources gestartet und wie folgt in der pom.xml eingebunden:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<!-- Aufruf: web3j:generate-sources--> <plugin> <groupId>org.web3j</groupId> <artifactId>web3j-maven-plugin</artifactId> <version>4.8.7</version> <configuration> <packageName>de.wenzlaff.blockchain.model</packageName> <sourceDestination>src/main/java/generated</sourceDestination> <nativeJavaType>true</nativeJavaType> <outputFormat>java,bin,abi</outputFormat> <soliditySourceFiles> <directory>src/main/resources</directory> <includes> <include>**/*.sol</include> </includes> </soliditySourceFiles> <outputDirectory> <java>src/main/java</java> <bin>src/bin/generated</bin> <abi>src/abi/generated</abi> </outputDirectory> <contract> <includes> <include></include> </includes> <excludes> <exclude></exclude> </excludes> </contract> <pathPrefixes> <pathPrefix>dep=../dependencies</pathPrefix> </pathPrefixes> </configuration> </plugin> </plugins> |
Nach dem generieren haben wir dann das generierte ABI im Json Format in der Datei Gehirn.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
[ { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [], "name": "getBedeutung", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getIQ", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "neuerIQ", "type": "uint256" } ], "name": "setIQ", "outputs": [], "stateMutability": "payable", "type": "function" } ] |
Und den binären Code in der Gehirn.bin der auch in dem generierten Java-Wrapper als public Konstante BINARY vorhanden ist:
1 |
608060405234801561001057600080fd5b5060646000556103d3806100256000396000f3fe6080604052600436106100345760003560e01c806303da5f75146100395780634035548114610060578063cfb996da1461007f575b600080fd5b34801561004557600080fd5b5061004e610109565b60408051918252519081900360200190f35b61007d6004803603602081101561007657600080fd5b5035610110565b005b34801561008b57600080fd5b50610094610115565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100ce5781810151838201526020016100b6565b50505050905090810190601f1680156100fb5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000545b90565b600055565b6060602860005411610150575060408051808201909152601281527112d95a5b9948105d5cdcd859d95adc98599d60721b602082015261010d565b6029600054101580156101665750604660005411155b1561018b5760405180606001604052806033815260200161036b60339139905061010d565b6047600054101580156101a15750604f60005411155b156101d857506040805180820190915260158152740eadce8cae4c8eae4c6d0e6c6d0dcd2e8e8d8d2c6d605b1b602082015261010d565b6050600054101580156101ee5750605960005411155b1561022d575060408051808201909152601b81527f657477617320756e74657264757263687363686e6974746c6963680000000000602082015261010d565b605a600054101580156102435750606d60005411155b15610271575060408051808201909152600c81526b111d5c98da1cd8da1b9a5d1d60a21b602082015261010d565b606e600054101580156102875750607760005411155b156102ad57506040805180820190915260048152630d0dec6d60e31b602082015261010d565b6078600054101580156102c35750608160005411155b156102ee57506040805180820190915260098152680e6cad0e440d0dec6d60bb1b602082015261010d565b6082600054101580156103045750609f60005411155b15610330575060408051808201909152600a8152691a1bd8da189959d8589d60b21b602082015261010d565b60a0600054111561010d575060408051808201909152601281527112d95a5b9948105d5cdcd859d95adc98599d60721b602082015261010d56fe5765697420756e74657264757263687363686e6974746c69636820e2809320476569737469676520426568696e646572756e67a2646970667358221220e47f5ca58cc85c126b32581ede151a0854e01cddae7e74c48381e24fa57c5ed964736f6c634300060c0033 |
Hier der Gehirn.java Wrapper, der für weitere Anwendungsfälle verwendet werden kann:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
package de.wenzlaff.blockchain.model; import java.math.BigInteger; import java.util.Arrays; import java.util.Collections; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.Function; import org.web3j.abi.datatypes.Type; import org.web3j.abi.datatypes.Utf8String; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.RemoteCall; import org.web3j.protocol.core.RemoteFunctionCall; import org.web3j.protocol.core.methods.response.TransactionReceipt; import org.web3j.tx.Contract; import org.web3j.tx.TransactionManager; import org.web3j.tx.gas.ContractGasProvider; /** * <p>Auto generated code. * <p><strong>Do not modify!</strong> * <p>Please use the <a href="https://docs.web3j.io/command_line.html">web3j command line tools</a>, * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the * <a href="https://github.com/web3j/web3j/tree/master/codegen">codegen module</a> to update. * * <p>Generated with web3j version 4.8.7. */ @SuppressWarnings("rawtypes") public class Gehirn extends Contract { public static final String BINARY = "608060405234801561001057600080fd5b5060646000556103d3806100256000396000f3fe6080604052600436106100345760003560e01c806303da5f75146100395780634035548114610060578063cfb996da1461007f575b600080fd5b34801561004557600080fd5b5061004e610109565b60408051918252519081900360200190f35b61007d6004803603602081101561007657600080fd5b5035610110565b005b34801561008b57600080fd5b50610094610115565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100ce5781810151838201526020016100b6565b50505050905090810190601f1680156100fb5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000545b90565b600055565b6060602860005411610150575060408051808201909152601281527112d95a5b9948105d5cdcd859d95adc98599d60721b602082015261010d565b6029600054101580156101665750604660005411155b1561018b5760405180606001604052806033815260200161036b60339139905061010d565b6047600054101580156101a15750604f60005411155b156101d857506040805180820190915260158152740eadce8cae4c8eae4c6d0e6c6d0dcd2e8e8d8d2c6d605b1b602082015261010d565b6050600054101580156101ee5750605960005411155b1561022d575060408051808201909152601b81527f657477617320756e74657264757263687363686e6974746c6963680000000000602082015261010d565b605a600054101580156102435750606d60005411155b15610271575060408051808201909152600c81526b111d5c98da1cd8da1b9a5d1d60a21b602082015261010d565b606e600054101580156102875750607760005411155b156102ad57506040805180820190915260048152630d0dec6d60e31b602082015261010d565b6078600054101580156102c35750608160005411155b156102ee57506040805180820190915260098152680e6cad0e440d0dec6d60bb1b602082015261010d565b6082600054101580156103045750609f60005411155b15610330575060408051808201909152600a8152691a1bd8da189959d8589d60b21b602082015261010d565b60a0600054111561010d575060408051808201909152601281527112d95a5b9948105d5cdcd859d95adc98599d60721b602082015261010d56fe5765697420756e74657264757263687363686e6974746c69636820e2809320476569737469676520426568696e646572756e67a2646970667358221220e47f5ca58cc85c126b32581ede151a0854e01cddae7e74c48381e24fa57c5ed964736f6c634300060c0033"; public static final String FUNC_GETBEDEUTUNG = "getBedeutung"; public static final String FUNC_GETIQ = "getIQ"; public static final String FUNC_SETIQ = "setIQ"; @Deprecated protected Gehirn(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); } protected Gehirn(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, credentials, contractGasProvider); } @Deprecated protected Gehirn(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); } protected Gehirn(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } public RemoteFunctionCall<String> getBedeutung() { final Function function = new Function(FUNC_GETBEDEUTUNG, Arrays.<Type>asList(), Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall<BigInteger> getIQ() { final Function function = new Function(FUNC_GETIQ, Arrays.<Type>asList(), Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall<TransactionReceipt> setIQ(BigInteger neuerIQ) { final Function function = new Function( FUNC_SETIQ, Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Uint256(neuerIQ)), Collections.<TypeReference<?>>emptyList()); return executeRemoteCallTransaction(function); } @Deprecated public static Gehirn load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { return new Gehirn(contractAddress, web3j, credentials, gasPrice, gasLimit); } @Deprecated public static Gehirn load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { return new Gehirn(contractAddress, web3j, transactionManager, gasPrice, gasLimit); } public static Gehirn load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { return new Gehirn(contractAddress, web3j, credentials, contractGasProvider); } public static Gehirn load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { return new Gehirn(contractAddress, web3j, transactionManager, contractGasProvider); } public static RemoteCall<Gehirn> deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { return deployRemoteCall(Gehirn.class, web3j, credentials, contractGasProvider, BINARY, ""); } public static RemoteCall<Gehirn> deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { return deployRemoteCall(Gehirn.class, web3j, transactionManager, contractGasProvider, BINARY, ""); } @Deprecated public static RemoteCall<Gehirn> deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { return deployRemoteCall(Gehirn.class, web3j, credentials, gasPrice, gasLimit, BINARY, ""); } @Deprecated public static RemoteCall<Gehirn> deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { return deployRemoteCall(Gehirn.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, ""); } } |
Als UML:
Weitere Anwendungsfälle in weiteren Teilen hier auf dem Blog. Hier liegt der Smart-Contract.