blob: b19e952fba9462cab8e379aeb5880995296bb729 [file] [log] [blame]
/*
* Copyright (c) Robert Bosch GmbH. All rights reserved.
*/
package org.eclipse.blockchain.core;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.apache.commons.io.FileUtils;
import org.eclipse.blockchain.classloader.DynamicClassLoader;
import org.eclipse.blockchain.core.events.BlockchainEnvironmentChangedTrigger;
import org.eclipse.blockchain.core.events.IBlockchainEnvironmentChangedEvent;
import org.eclipse.blockchain.core.events.IBlockchainEnvironmentChangedListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Event;
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.evm.Configuration;
import org.web3j.evm.EmbeddedWeb3jService;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.Web3jService;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.admin.methods.response.NewAccountIdentifier;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.DefaultBlockParameterNumber;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.Log;
import org.web3j.protocol.core.methods.response.Transaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.ipc.WindowsIpcService;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Convert;
import org.web3j.utils.Convert.Unit;
import org.web3j.utils.Numeric;
/**
* @author ADG5COB
*/
public class Web3jHandler implements IBlockchainEnvironmentChangedListener {
private final Account personalAccount = new Account();
private String eventInfo = "";
private static Web3jHandler web3j;
private final List<String> accountPassword = new ArrayList<>();
/**
* Environment based contract and class instance maps. Currently there are 2 types 1. EnvironmentType.GETH_CLIENT 2.
* EnvironmentType.EMBEDDED_EVM
*/
private final Map<String, Map<String, Class<?>>> environmentBasedContractMap = new HashMap<>();
private final Map<String, Map<String, Object>> environmentBasedClassInstanceMap = new HashMap<>();
private EmbeddedEVMObject embeddedEVM = null;
private String selectedEnvironment = "";
private Web3jHandler() {}
/**
* @return -
*/
public static Web3jHandler getInstance() {
if (web3j == null) {
web3j = new Web3jHandler();
web3j.initializeEVMConfigurationMap();
BlockchainEnvironmentChangedTrigger.getInstance().addBlockchainEnvironmentChangedListener(web3j);
}
if (web3j.accountPassword.isEmpty()) {
web3j.accountPassword.add("123");
web3j.accountPassword.add("123");
web3j.accountPassword.add("123");
}
return web3j;
}
/**
* Before calling this method make sure Geth server is started
*
* @throws IOException -
* @throws InterruptedException -
* @throws ExecutionException -
*/
public String createInitialAccounts() throws IOException, InterruptedException, ExecutionException {
while (true) {
if (CoreCommandExecutor.getInstance().isGethStarted()) {
break;
}
if (!CoreCommandExecutor.getInstance().getGethServerStartError().replace("Geth", "").isEmpty()) {
return CoreCommandExecutor.getInstance().getGethServerStartError().replace("Geth", "");
}
Thread.sleep(500);
}
List<String> result = getAdminInstance().personalListAccounts().send().getResult();
if (result.isEmpty()) {
// Then no accounts in the data directory create new accounts
NewAccountIdentifier account1 = getAdminInstance().personalNewAccount("123").send();
NewAccountIdentifier account2 = getAdminInstance().personalNewAccount("123").send();
NewAccountIdentifier account3 = getAdminInstance().personalNewAccount("123").send();
Map<String, String> accountsMap = new LinkedHashMap<>();
accountsMap.put(account1.getAccountId(), "123");
accountsMap.put(account2.getAccountId(), "123");
accountsMap.put(account3.getAccountId(), "123");
this.personalAccount.setDataDir(SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString(),
CoreCommandExecutor.getInstance().getDataDir());
this.personalAccount.setAccounts(SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString(),
accountsMap);
// Terminate geth server
CoreCommandExecutor.getInstance().terminateGethServer();
while (true) {
if (!CoreCommandExecutor.getInstance().isGethStarted()) {
break;
}
Thread.sleep(500);
}
// Start new geth server with new accounts created above
CoreCommandExecutor.getInstance().startGethServer(CoreCommandExecutor.getInstance().getDataDir(),
createGethInitFile(CoreCommandExecutor.getInstance().getDataDir(), true,
SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString()),
CoreCommandExecutor.getInstance().getGethOptions());
while (true) {
if (CoreCommandExecutor.getInstance().isGethStarted()) {
break;
}
if (!CoreCommandExecutor.getInstance().getGethServerStartError().replace("Geth", "").isEmpty()) {
return CoreCommandExecutor.getInstance().getGethServerStartError().replace("Geth", "");
}
Thread.sleep(500);
}
Map<String, String> balanceMap = new LinkedHashMap<>();
balanceMap.put(account1.getAccountId(), convertToEther(getAdminInstance()
.ethGetBalance(account1.getAccountId(), new DefaultBlockParameterNumber(0)).send().getBalance().toString()));
balanceMap.put(account2.getAccountId(), convertToEther(getAdminInstance()
.ethGetBalance(account2.getAccountId(), new DefaultBlockParameterNumber(0)).send().getBalance().toString()));
balanceMap.put(account3.getAccountId(), convertToEther(getAdminInstance()
.ethGetBalance(account3.getAccountId(), new DefaultBlockParameterNumber(0)).send().getBalance().toString()));
this.personalAccount.setAccountBalance(SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString(),
balanceMap);
// Unlock newly created accounts
getAdminInstance().personalUnlockAccount(account1.getAccountId(), "123");
getAdminInstance().personalUnlockAccount(account2.getAccountId(), "123");
getAdminInstance().personalUnlockAccount(account3.getAccountId(), "123");
}
else {
// Accounts are already present load them
Map<String, String> accountsMap = new LinkedHashMap<>();
Map<String, String> balanceMap = new LinkedHashMap<>();
String[] account = new String[3];
for (int i = 0; i < result.size(); i++) {
accountsMap.put(result.get(i), this.accountPassword.get(i));
account[i] = result.get(i);
}
balanceMap.put(account[0], convertToEther(getAdminInstance()
.ethGetBalance(account[0], DefaultBlockParameterName.LATEST).sendAsync().get().getBalance().toString()));
balanceMap.put(account[1], convertToEther(getAdminInstance()
.ethGetBalance(account[1], DefaultBlockParameterName.LATEST).sendAsync().get().getBalance().toString()));
balanceMap.put(account[2], convertToEther(getAdminInstance()
.ethGetBalance(account[2], DefaultBlockParameterName.LATEST).sendAsync().get().getBalance().toString()));
this.personalAccount.setAccountBalance(SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString(),
balanceMap);
this.personalAccount.setDataDir(SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString(),
CoreCommandExecutor.getInstance().getDataDir());
this.personalAccount.setAccounts(SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString(),
accountsMap);
getAdminInstance().personalUnlockAccount(account[0], "123");
getAdminInstance().personalUnlockAccount(account[1], "123");
getAdminInstance().personalUnlockAccount(account[2], "123");
}
// add listener for tranactions
addListenerForTransactions();
return "";
}
/**
* @param projectName -
* @param scName -
* @param solOutputDir -
* @param solidityFileAbsPath -
* @param values -
* @param accountDetails -
* @return -
* @throws Exception -
*/
public String deploySmartContract(final String projectName, final String scName, final String solOutputDir,
final String solidityFileAbsPath, final String values, final String accountDetails)
throws Exception {
try {
if ((getSelectedEnvironment().equals(SecoBlocksPreferenceConstants.EnvironmentType.GETH_CLIENT.toString())) &&
(!CoreCommandExecutor.getInstance().isGethStarted())) {
return "Geth Server is not started";
}
Class<?> contract;
Object classInstance;
Web3j web3jLocal = getWeb3jInstance();
Map<String, String> accounts = this.personalAccount.getAccounts(getSelectedEnvironment());
Iterator<String> iterator = accounts.keySet().iterator();
String accountInfo = null;
while (iterator.hasNext()) {
String account = iterator.next();
if (account.equals(accountDetails)) {
accountInfo = account;
break;
}
}
if (accountInfo != null) {
String[] credentials = getWalletFile(accountInfo.replace("0x", ""),
this.personalAccount.getDataDir(getSelectedEnvironment()) + File.separator + "keystore").split("~");
Credentials creds = WalletUtils.loadCredentials(credentials[1], credentials[0]);
ContractGasProvider contractGasProvider = new DefaultGasProvider();
DynamicClassLoader dcl = new DynamicClassLoader(this.getClass().getClassLoader(), projectName, solOutputDir);
contract = dcl.loadClass("com.bosch." + scName);
SolidityABI[] solABI = CoreCommandExecutor.getInstance().getSolABIMap(solidityFileAbsPath);
Class<?>[] cls = getConstructorArgTypes(solABI);
Object[] objs = getConstructorArgsAsObject(solABI, web3jLocal, creds, contractGasProvider, values);
RemoteCall<?> dep = (RemoteCall<?>) contract.getMethod("deploy", cls).invoke(contract, objs);
if (!SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString().equals(getSelectedEnvironment())) {
CoreCommandExecutor.getInstance().mine(true);
}
classInstance = dep.send();
EthereumProject ethProject = ProjectCreator.getInstance().getEthProject(projectName);
ethProject.createDeploymentModel(contract.getMethod("getContractAddress").invoke(classInstance).toString(),
ethProject.getProject()
.getFile(solidityFileAbsPath.replace(ethProject.getProject().getLocation().toOSString(), "")),
accountInfo, getSelectedEnvironment());
Map<String, Class<?>> tempContractMap =
this.environmentBasedContractMap.computeIfAbsent(getSelectedEnvironment(), m -> new HashMap<>());
tempContractMap.put(solidityFileAbsPath, contract);
Map<String, Object> tempClassInstanceMap =
this.environmentBasedClassInstanceMap.computeIfAbsent(getSelectedEnvironment(), m -> new HashMap<>());
tempClassInstanceMap.put(solidityFileAbsPath, classInstance);
}
}
finally {
updateAccBalance();
if (!SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString().equals(getSelectedEnvironment())) {
CoreCommandExecutor.getInstance().mine(false);
}
}
return "";
}
/**
* @throws IOException
* @throws ExecutionException
* @throws InterruptedException
*/
private void updateAccBalance() throws InterruptedException, ExecutionException {
Map<String, String> accountBalance = this.personalAccount.getAccountBalance(getSelectedEnvironment());
Iterator<String> iterator = accountBalance.keySet().iterator();
while (iterator.hasNext()) {
String accountID = iterator.next();
if (SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString().equals(getSelectedEnvironment())) {
accountBalance.put(accountID, convertToEther(getWeb3jInstance()
.ethGetBalance(accountID, DefaultBlockParameterName.LATEST).sendAsync().get().getBalance().toString()));
}
else {
accountBalance.put(accountID, convertToEther(getAdminInstance()
.ethGetBalance(accountID, DefaultBlockParameterName.LATEST).sendAsync().get().getBalance().toString()));
}
}
}
private Class<?>[] getConstructorArgTypes(final SolidityABI[] solABI) {
Class<?>[] classType = null;
for (SolidityABI sAbi : solABI) {
if (sAbi.getType().equalsIgnoreCase("constructor")) {
int inpsLength = sAbi.getInputs().length;
classType = new Class<?>[inpsLength + 3];
classType[0] = Web3j.class;
classType[1] = Credentials.class;
classType[2] = ContractGasProvider.class;
for (int i = 3; i < (inpsLength + 3); i++) {
classType[i] = sAbi.getInputs()[(i - 3)].getJavaType();
}
}
}
if (classType == null) {// Contracts w/o constructor
classType = new Class<?>[3];
classType[0] = Web3j.class;
classType[1] = Credentials.class;
classType[2] = ContractGasProvider.class;
}
return classType;
}
private Object[] getConstructorArgsAsObject(final SolidityABI[] solABI, final Web3j web3jLocal,
final Credentials creds, final ContractGasProvider contractGasProvider, final String values) {
Object[] objs = null;
String[] inputVals = values.split(";");
for (SolidityABI sAbi : solABI) {
if (sAbi.getType().equalsIgnoreCase("constructor")) {
int inpsLength = sAbi.getInputs().length;
objs = new Object[inpsLength + 3];
objs[0] = web3jLocal;
objs[1] = creds;
objs[2] = contractGasProvider;
for (int i = 3; i < (inpsLength + 3); i++) {
objs[i] = getVariable(inputVals[(i - 3)], sAbi.getInputs()[(i - 3)].getJavaType(),
sAbi.getInputs()[(i - 3)].getCastType(), sAbi.getInputs()[(i - 3)].getIsArray());
}
}
}
if (objs == null) {// Contracts w/o constructor
objs = new Object[3];
objs[0] = web3jLocal;
objs[1] = creds;
objs[2] = contractGasProvider;
}
return objs;
}
private Object getVariable(final String value, final Class<?> type, final Class<?> castType, final boolean isArray) {
Object castValue = null;
castValue = SolidityDynamicValueCasterHandler.getValue(value, (isArray ? castType : type), isArray);
return castValue;
}
/**
* This method is used to invoke the smart contract function...
*
* @param projectName -
* @param funcName
* @param scAbsPath
* @param values - The input params for the function to be invoked, should be a comma separated value.
* @param accountDetails -
* @return
* @throws Exception
*/
public String invokeSCFunction(final String projectName, final String funcName, final String scAbsPath,
final String values, final String accountDetails)
throws Exception {
String response = "";
Object responseObject = null;
boolean returnPresent = false;
Map<String, Class<?>> tempContractMap =
this.environmentBasedContractMap.computeIfAbsent(getSelectedEnvironment(), m -> new HashMap<>());
Class<?> contract = tempContractMap.get(scAbsPath);
Map<String, Object> tempClassInstanceMap =
this.environmentBasedClassInstanceMap.computeIfAbsent(getSelectedEnvironment(), m -> new HashMap<>());
Object classInstance = tempClassInstanceMap.get(scAbsPath);
try {
String[] funcDetails = funcName.split("-");
String argList = "";
if (funcDetails.length > 1) {
argList = funcDetails[1];
}
SolidityABI[] solABI = CoreCommandExecutor.getInstance().getSolABIMap(scAbsPath);
String[] inputVals = new String[0];
if (!values.isEmpty()) {
inputVals = values.split(";");
}
SolidityABI masterSolABI = getSolABI(solABI, funcDetails[0], argList, inputVals);
if (masterSolABI != null) {
Class<?>[] funcArgs = getFuncArgs(masterSolABI);
EthereumProject ethProject = ProjectCreator.getInstance().getEthProject(projectName);
// Re-Load contract with new credentials - if different account is chosen
String lastUsedAccount = ethProject.getLastUsedAccount(
ethProject.getProject().getFile(scAbsPath.replace(ethProject.getProject().getLocation().toOSString(), "")),
getSelectedEnvironment());
if (!accountDetails.equals(lastUsedAccount)) {
String[] credentials = getWalletFile(accountDetails.replace("0x", ""),
this.personalAccount.getDataDir(getSelectedEnvironment()) + File.separator + "keystore").split("~");
Web3j web3jInstance = getWeb3jInstance();
Credentials creds = WalletUtils.loadCredentials(credentials[1], credentials[0]);
ContractGasProvider contractGasProvider = new DefaultGasProvider();
classInstance =
contract.getMethod("load", String.class, Web3j.class, Credentials.class, ContractGasProvider.class)
.invoke(classInstance,
ethProject.getContractAddress(
ethProject.getProject()
.getFile(scAbsPath.replace(ethProject.getProject().getLocation().toOSString(), "")),
getSelectedEnvironment()),
web3jInstance, creds, contractGasProvider);
ethProject.updateLastUsedAccount(
ethProject.getProject()
.getFile(scAbsPath.replace(ethProject.getProject().getLocation().toOSString(), "")),
accountDetails, getSelectedEnvironment());
/**
* This is required because when account is changed(Acc1 to Acc2) the classInstance will be loaded here with
* the new account(Acc2) and hence the tempclassinstancemap should also be updated with the newly loaded
* classinstance
*/
tempClassInstanceMap.put(scAbsPath, classInstance);
}
RemoteCall<?> dep = (RemoteCall<?>) contract.getMethod(funcDetails[0], funcArgs).invoke(classInstance,
getFuncValues(values, masterSolABI.getInputs()));
returnPresent = doesFunctionReturnSomething(masterSolABI);
if (!SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString().equals(getSelectedEnvironment())) {
CoreCommandExecutor.getInstance().mine(true);
}
// response = dep.send().toString();
responseObject = dep.send();
// responseObject = SolidityDynamicValueCasterHandler.getValue(projectName, valueToCast, actualType, isArray)
if (returnPresent && masterSolABI.getOutputs()[0].getJavaType().equals(List.class) &&
masterSolABI.getOutputs()[0].getCastType().getSimpleName().contains("byte")) {
List<byte[]> bytes = (List<byte[]>) responseObject;
for (byte[] b : bytes) {
response += Numeric.toHexString(b) + ";";
}
}
else if (returnPresent && masterSolABI.getOutputs()[0].getJavaType().getSimpleName().contains("byte")) {
response = Numeric.toHexString((byte[]) responseObject);
}
else {
response = responseObject.toString();
}
}
else {
returnPresent = true;
response = "Something is not rite. Please make sure you pass the correct arguments";
}
this.eventInfo = "";
TransactionReceipt transactionReceipt = (TransactionReceipt) responseObject;
ArrayList<Event> events = new ArrayList<Event>();
java.lang.reflect.Field[] s = classInstance.getClass().getFields();
for (Field field : s) {
if (field.getType() == Event.class) {
events.add((Event) field.get(this));
}
}
for (Event event : events) {
if (transactionReceipt != null) {
List<List<org.web3j.abi.datatypes.Type>> eventValues = new ArrayList<>();
List<org.web3j.abi.datatypes.Type> nonIndexed = null, Indexed = null;
List<Log> logs = transactionReceipt.getLogs();
for (Log log : logs) {
try {
nonIndexed = FunctionReturnDecoder.decode(log.getData(), event.getNonIndexedParameters());
Indexed = FunctionReturnDecoder.decode(log.getData(), event.getIndexedParameters());
}
catch (Exception e) {
continue;
}
}
if (!nonIndexed.isEmpty()) {
eventValues.add(nonIndexed);
}
if (!Indexed.isEmpty()) {
eventValues.add(Indexed);
}
for (List<org.web3j.abi.datatypes.Type> listType : eventValues) {
for (org.web3j.abi.datatypes.Type type : listType) {
this.eventInfo = this.eventInfo + event.getName() + "\t" + "Type " + type.getTypeAsString() + "\t" +
" Value " + type.getValue() + "\n";
}
}
}
}
}
finally {
updateAccBalance();
if (!SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString().equals(getSelectedEnvironment())) {
CoreCommandExecutor.getInstance().mine(false);
}
}
return (returnPresent) ? response : "DONE";
}
/**
* @return Event Information
*/
public String getEvents() {
if (this.eventInfo != null) {
return this.eventInfo;
}
return "No Event Information";
}
/**
* As of now restricted to String check....
*
* @param masterSolABI
* @param funcName
* @return
*/
private boolean doesFunctionReturnSomething(final SolidityABI masterSolABI) {
if (masterSolABI.getOutputs().length > 0) {
for (IOABI iob : masterSolABI.getOutputs()) {
if ((iob.getJavaType() != null) && !iob.getJavaType().getSimpleName().isEmpty()) {
return true;
}
}
return false;
}
return false;
}
private Class<?>[] getFuncArgs(final SolidityABI solABI) {
Class<?>[] argTypes = null;
IOABI[] inputs = solABI.getInputs();
argTypes = new Class[inputs.length];
for (int i = 0; i < inputs.length; i++) {
argTypes[i] = inputs[i].getJavaType();
}
return argTypes;
}
private SolidityABI getSolABI(final SolidityABI solABI[], final String funcName, final String argsList,
final String[] inputVals) {
List<String> inputArgs = new ArrayList<>();
if (argsList.contains(";")) {
inputArgs = Arrays.asList(argsList.split(";"));
}
else if (!argsList.isEmpty()) {
inputArgs.add(argsList);
}
for (SolidityABI sAbi : solABI) {
if (sAbi.getName().equalsIgnoreCase(funcName) && (sAbi.getInputs().length == inputVals.length)) {
List<String> argVals = new ArrayList<>();
for (IOABI input : sAbi.getInputs()) {
argVals.add(input.getJavaType().getSimpleName());
}
if (inputArgs.equals(argVals)) {
return sAbi;
}
}
}
return null;
}
private Object[] getFuncValues(final String values, final IOABI[] ioabi) {
if (values.isEmpty()) {
return null;
}
String[] inputVals = values.split(";");
Object[] vals = new Object[inputVals.length];
for (int i = 0; i < inputVals.length; i++) {
vals[i] = getVariable(inputVals[i], ioabi[i].getJavaType(), ioabi[i].getCastType(), ioabi[i].getIsArray());
}
return vals;
}
private String convertToEther(final String wei) {
return Convert.fromWei(wei, Unit.ETHER).toString();
}
private String createGethInitFile(final String dataDir, final boolean clearOldData, final String accountType)
throws IOException, InterruptedException {
if (clearOldData) {
clearOldDataDir(dataDir);
}
File gethInitFile = new File(dataDir + File.separator + "genesis.json");
gethInitFile.createNewFile();// NOSONAR
List<String> accounts = new ArrayList<>(this.personalAccount.getAccounts(accountType).keySet());
try (
BufferedReader br = new BufferedReader(
new InputStreamReader(CoreCommandExecutor.class.getResourceAsStream("genesis2.template")));
BufferedWriter bw = new BufferedWriter(new FileWriter(gethInitFile));) {
String genesisContent = "";
while ((genesisContent = br.readLine()) != null) {
if (genesisContent.contains("acc")) {
int index = Integer
.parseInt(genesisContent.substring(genesisContent.indexOf("acc") + 3, genesisContent.indexOf("acc") + 4));
genesisContent = genesisContent.replace("acc" + index, accounts.get(index));
}
bw.append(genesisContent);
bw.append(System.lineSeparator());
}
}
return gethInitFile.getAbsolutePath();
}
private static void clearOldDataDir(final String dataDir) throws IOException, InterruptedException {
int maxTries = 3;
while (maxTries >= 1) {
try {
FileUtils.deleteDirectory(new File(dataDir + File.separator + "geth"));
break;
}
catch (IOException e) {
if (maxTries > 1) {
maxTries--;
Thread.sleep(500);
}
else {
throw e;
}
}
}
new File(dataDir + File.separator + "genesis.json").delete();// NOSONAR
}
/**
* Returns account wallet file along with its password walletFile~password
*
* @param accId
* @param keyStore
* @return
*/
private String getWalletFile(final String accId, final String keyStore) {
File directory = new File(keyStore);
File[] listFiles = directory.listFiles();
for (File f : listFiles) {
if (f.getName().contains(accId)) {
return f.getAbsolutePath() + "~" + this.personalAccount.getAccounts(getSelectedEnvironment()).get("0x" + accId);
}
}
return "";
}
/**
* @return - The personal accounts
*/
public Account getAccount() {
return this.personalAccount;
}
/**
* As of now only single account is supported in embeddedEVM
*/
private void initializeEVMConfigurationMap() {
try {
String workspaceLocation = ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString();
File evmWalletLocation =
new File(workspaceLocation + File.separator + "evmWalletLocation" + File.separator + "keystore");
if (evmWalletLocation.exists()) {
Files.walkFileTree(Paths.get(evmWalletLocation.getAbsolutePath()), new SimpleFileVisitor<Path>() {
/**
* {@inheritDoc}
*/
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
/**
* {@inheritDoc}
*/
@Override
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
evmWalletLocation.mkdirs();
// WalletFiles creation
String walletFile1 = WalletUtils.generateFullNewWalletFile("123", evmWalletLocation);
String walletFile2 = WalletUtils.generateFullNewWalletFile("123", evmWalletLocation);
String walletFile3 = WalletUtils.generateFullNewWalletFile("123", evmWalletLocation);
// Credentials object
Credentials cred1 = WalletUtils.loadCredentials("123",
new File(evmWalletLocation.getAbsolutePath() + File.separator + walletFile1));
Credentials cred2 = WalletUtils.loadCredentials("123",
new File(evmWalletLocation.getAbsolutePath() + File.separator + walletFile2));
Credentials cred3 = WalletUtils.loadCredentials("123",
new File(evmWalletLocation.getAbsolutePath() + File.separator + walletFile3));
// Accounts updation
Map<String, String> accountsMap = new LinkedHashMap<>();
accountsMap.put(cred1.getAddress(), "123");
accountsMap.put(cred2.getAddress(), "123");
accountsMap.put(cred3.getAddress(), "123");
this.personalAccount.setAccounts(SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString(),
accountsMap);
Map<String, String> accountBalanceMap = new LinkedHashMap<>();
accountBalanceMap.put(cred1.getAddress(), "100");
accountBalanceMap.put(cred2.getAddress(), "100");
accountBalanceMap.put(cred3.getAddress(), "100");
this.personalAccount.setAccountBalance(SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString(),
accountBalanceMap);
this.personalAccount.setDataDir(SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString(),
evmWalletLocation.getParent());
// genesis file creation
String genesisFile = createGethInitFile(evmWalletLocation.getParent(), false,
SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString());
// Config object
Configuration config1 =
new Configuration(new Address(cred1.getAddress()), 100, new File(genesisFile).toURI().toURL());
Web3jService embeddedWeb3jService = new EmbeddedWeb3jService(config1);
Web3j web1 = Web3j.build(embeddedWeb3jService);
Admin admin1 = Admin.build(new EmbeddedWeb3jService(config1));
this.embeddedEVM = new EmbeddedEVMObject(config1, web1, admin1);
/**
* Transaction flowable is not supported by embedded EVM hence it is commented for now
*/
// addListenerForTransactions();
}
catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException
| CipherException | InterruptedException e) {
BlockchainCore.getInstance().logException(BlockchainCore.PLUGIN_ID, "Exception in evm config initialization", e);
}
}
/**
* @return - The environment web3j instance, if selected environment is geth then geth server should be started else
* null will be returned
*/
public Web3j getWeb3jInstance() {
if (getSelectedEnvironment().equals(SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString())) {
return this.embeddedEVM.getWeb3j();
}
if (CoreCommandExecutor.getInstance().isGethStarted()) {
return Web3j.build(new WindowsIpcService(CoreCommandExecutor.getInstance().getIPCPath()));
}
return null;
}
/**
* @return - The environment Admin instance, if selected environment is geth then geth server should be started else
* null will be returned
*/
public Admin getAdminInstance() {
if (getSelectedEnvironment().equals(SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString())) {
return this.embeddedEVM.getAdmin();
}
if (CoreCommandExecutor.getInstance().isGethStarted()) {
return Admin.build(new WindowsIpcService(CoreCommandExecutor.getInstance().getIPCPath()));
}
return null;
}
/**
* @return -
*/
public BigInteger getGasPrice() {
BigInteger gasPrice = null;
try {
gasPrice = getAdminInstance().ethGasPrice().send().getGasPrice();
}
catch (IOException e) {
BlockchainCore.getInstance().logException("", e.getMessage(), e);
}
return gasPrice;
}
private void addListenerForTransactions() {
getWeb3jInstance().transactionFlowable().subscribe(tx -> {
addToGlobalTransactionMap(tx);
});
}
/**
* Get transaction receipt for already mined transaction
*
* @param transactionHash - The transaction hash
* @return - The transaction receipt for the requested transaction
* @throws IOException - Is thrown if socket connection get terminated
*/
public String getTransactionReceiptAsString(final String transactionHash) throws IOException {
EthGetTransactionReceipt transactionReceipt = getWeb3jInstance().ethGetTransactionReceipt(transactionHash).send();
return getTransactionReceiptMessage(transactionReceipt.getResult());
}
private String getTransactionReceiptMessage(final TransactionReceipt transactionReceipt) {
return "Transaction Hash :" + transactionReceipt.getTransactionHash() + System.lineSeparator() +
"Transaction Index :" + transactionReceipt.getTransactionIndex() + System.lineSeparator() + "Block Hash :" +
transactionReceipt.getBlockHash() + System.lineSeparator() + "Block Number :" +
transactionReceipt.getBlockNumber() + System.lineSeparator() + "Cumulative Gas Used :" +
transactionReceipt.getCumulativeGasUsed() + System.lineSeparator() + "Gas Used :" +
transactionReceipt.getGasUsed() + System.lineSeparator() + "Contract Address :" +
transactionReceipt.getContractAddress() + System.lineSeparator() + "Root :" + transactionReceipt.getRoot() +
System.lineSeparator() + "Status :" + transactionReceipt.getStatus() + System.lineSeparator() + "From :" +
transactionReceipt.getFrom() + System.lineSeparator() + "To :" + transactionReceipt.getTo() +
System.lineSeparator() + "Logs :" + transactionReceipt.getLogs().toString() + System.lineSeparator() +
"Logs Bloom :" + transactionReceipt.getLogsBloom() + System.lineSeparator();
}
/**
* @param tx
*/
private void addToGlobalTransactionMap(final Transaction tx) {
// create an intermediate transaction model with the actual transaction data
TransactionModel transactionModel = new TransactionModel();
transactionModel.setValues(tx);
// refresh the transaction view with data
BlockchainViewsRegistry.getListOFViews().stream().forEach(view -> view.updateView(transactionModel));
}
String getSelectedEnvironment() {
if (!this.selectedEnvironment.isEmpty()) {
return this.selectedEnvironment;
}
return this.selectedEnvironment = InstanceScope.INSTANCE.getNode(SecoBlocksPreferenceConstants.SECOBLOCKS_PREF_NODE)
.get(SecoBlocksPreferenceConstants.ENVIRONMENT_PREF_KEY,
SecoBlocksPreferenceConstants.EnvironmentType.EMBEDDED_EVM.toString());
}
/**
* {@inheritDoc}
*/
@Override
public void blockchainEnvironmentChanged(final IBlockchainEnvironmentChangedEvent event) {
this.selectedEnvironment = event.getActiveEvironment();
}
}