Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.cryptape.cita.protocol.account.Account Maven / Gradle / Ivy
package com.cryptape.cita.protocol.account;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
import com.cryptape.cita.abi.datatypes.Function;
import com.cryptape.cita.abi.datatypes.Type;
import com.cryptape.cita.abi.datatypes.UnorderedEvent;
import com.cryptape.cita.crypto.Credentials;
import com.cryptape.cita.protocol.CITAj;
import com.cryptape.cita.protocol.core.DefaultBlockParameter;
import com.cryptape.cita.protocol.core.DefaultBlockParameterName;
import com.cryptape.cita.protocol.core.methods.request.AppFilter;
import com.cryptape.cita.protocol.core.methods.request.Call;
import com.cryptape.cita.protocol.core.methods.response.AppCall;
import com.cryptape.cita.protocol.core.methods.response.AppSendTransaction;
import com.cryptape.cita.protocol.core.methods.response.Log;
import com.cryptape.cita.tx.RawTransactionManager;
import com.cryptape.cita.utils.TypedAbi;
import io.reactivex.Flowable;
import com.cryptape.cita.abi.EventEncoder;
import com.cryptape.cita.abi.EventValues;
import com.cryptape.cita.abi.FunctionEncoder;
import com.cryptape.cita.abi.FunctionReturnDecoder;
import com.cryptape.cita.abi.TypeReference;
import com.cryptape.cita.protocol.core.methods.response.AbiDefinition;
public class Account {
private static final String ABI_ADDRESS = "ffffffffffffffffffffffffffffffffff010001";
private RawTransactionManager transactionManager;
private CITAj service;
private String abi;
public Account(String privateKey, CITAj service) {
Credentials credentials = Credentials.create(privateKey);
this.transactionManager = new RawTransactionManager(service, credentials);
this.service = service;
}
public RawTransactionManager getTransactionManager() {
return transactionManager;
}
/// TODO: get contract address from receipt after deploy, then return contract name
public AppSendTransaction deploy(
File contractFile, String nonce, long quota,
int version, BigInteger chainId, String value)
throws IOException, InterruptedException, CompiledContract.ContractCompileError {
CompiledContract contract = new CompiledContract(contractFile);
String contractBin = contract.getBin();
return this.transactionManager
.sendTransaction("", contractBin, quota, nonce, getValidUntilBlock(),
version, chainId, value);
}
public Flowable deployAsync(
File contractFile, String nonce, long quota,
int version, BigInteger chainId, String value)
throws IOException, InterruptedException, CompiledContract.ContractCompileError {
CompiledContract contract = new CompiledContract(contractFile);
String contractBin = contract.getBin();
return this.transactionManager
.sendTransactionAsync("", contractBin, quota, nonce, getValidUntilBlock(),
version, chainId, value);
}
// sendTransaction: nonce and quota is necessary
public Object callContract(
String contractAddress, String funcName,
String nonce, long quota, int version,
BigInteger chainId, String value, Object... args)
throws Exception {
if (abi == null) {
abi = getAbi(contractAddress);
}
CompiledContract contract = new CompiledContract(abi);
AbiDefinition functionAbi = contract.getFunctionAbi(funcName, args.length);
return callContract(
contractAddress, functionAbi, nonce, quota, version, chainId, value, args);
}
public Object callContract(
String contractAddress, AbiDefinition functionAbi,
String nonce, long quota,
int version,BigInteger chainId, String value, Object... args)
throws Exception {
List params = new ArrayList<>();
List inputs = functionAbi.getInputs();
for (int i = 0; i < inputs.size(); i++) {
Object arg = args[i];
String typeName = inputs.get(i).getType();
params.add(TypedAbi.getType(typeName, arg));
}
Function func;
if (functionAbi.isConstant()) {
// call
List retsType = new ArrayList<>();
List> retsTypeRef = new ArrayList<>();
List outputs = functionAbi.getOutputs();
for (AbiDefinition.NamedType namedType: outputs) {
TypedAbi.ArgRetType retType = TypedAbi.getArgRetType(namedType.getType());
retsType.add(retType);
retsTypeRef.add(retType.getTypeReference());
}
func = new Function(functionAbi.getName(), params, retsTypeRef);
return appCall(contractAddress, func, retsType);
} else {
// send_transaction
func = new Function(functionAbi.getName(), params, Collections.emptyList());
return sendTransaction(
contractAddress, func, nonce, quota, version, chainId, value);
}
}
public Object appCall(String contractAddress, Function func, List retsType)
throws IOException {
String data = FunctionEncoder.encode(func);
AppCall call = this.service.appCall(new Call(this.transactionManager.getFromAddress(),
contractAddress, data), DefaultBlockParameterName.PENDING).send();
String value = call.getValue();
List abiValues = FunctionReturnDecoder.decode(value, func.getOutputParameters());
if (retsType.size() == 1) {
return retsType.get(0).abiToJava(abiValues.get(0));
} else {
List results = new ArrayList<>();
for (int i = 0; i < retsType.size(); i++) {
results.add(retsType.get(i).abiToJava(abiValues.get(i)));
}
return results;
}
}
public Object sendTransaction(
String contractAddress, Function func, String nonce,
long quota, int version, BigInteger chainId, String value)
throws IOException {
String data = FunctionEncoder.encode(func);
return this.transactionManager.sendTransaction(
contractAddress, data, quota, nonce, getValidUntilBlock(),
version, chainId, value);
}
public Object uploadAbi(
String contractAddress, String abi, String nonce, long quota,
int version, BigInteger chainId, String value) throws Exception {
String data = hex_remove_0x(contractAddress) + hex_remove_0x(bytesToHexStr(abi.getBytes()));
return this.transactionManager.sendTransaction(
ABI_ADDRESS, data, quota, nonce, getValidUntilBlock(),
version, chainId, value);
}
public String getAbi(String contractAddress) throws IOException {
String abi = service.appGetAbi(
contractAddress, DefaultBlockParameterName.PENDING).send().getAbi();
return new String(hexStrToBytes(hex_remove_0x(abi)));
}
public Flowable eventFlowable(String contractName, String eventName)
throws Exception {
CompiledContract contract = loadContract(contractName);
String contractAddress = getContractAddress(contractName);
AbiDefinition eventAbi = contract.getEventAbi(eventName);
return eventFlowable(
contractAddress, eventAbi,
DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.PENDING);
}
public Flowable eventFlowable(String contractAddress, AbiDefinition eventAbi,
DefaultBlockParameter start,
DefaultBlockParameter end)
throws Exception {
List results = new ArrayList<>();
List namedTypes = eventAbi.getInputs();
UnorderedEvent event = new UnorderedEvent(eventAbi.getName());
for (AbiDefinition.NamedType namedType: namedTypes) {
TypedAbi.ArgRetType argRetType = TypedAbi.getArgRetType(namedType.getType());
results.add(argRetType);
event.add(namedType.isIndexed(), argRetType.getTypeReference());
}
AppFilter filter = new AppFilter(start, end, contractAddress);
/// FIXME: https://github.com/web3j/web3j/issues/209, patch to this after cita fixed
filter.addSingleTopic(EventEncoder.encode(event));
return this.service.appLogFlowable(filter).map(new io.reactivex.functions.Function() {
@Override
public Object apply(Log log) throws Exception {
EventValues eventValues = staticExtractEventParameters(event, log);
List indexedValues = eventValues.getIndexedValues();
List nonIndexedValues = eventValues.getNonIndexedValues();
int indexedSize = indexedValues.size();
int nonIndexedSize = nonIndexedValues.size();
int size = indexedSize + nonIndexedSize;
List values = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
values.add(null);
}
List indexedSeq = event.getIndexedParametersSeq();
for (int i = 0; i < indexedSize; i++) {
int indexSeqNum = indexedSeq.get(i);
values.set(
indexSeqNum, results.get(indexSeqNum).abiToJava(indexedValues.get(i)));
}
List nonIndexedSeq = event.getNonIndexedParametersSeq();
for (int i = 0; i < nonIndexedSize; i++) {
int indexSeqNum = nonIndexedSeq.get(i);
values.set(
indexSeqNum, results.get(indexSeqNum).abiToJava(nonIndexedValues.get(i)));
}
return values;
}
});
}
private static EventValues staticExtractEventParameters(
UnorderedEvent event, Log log) {
List topics = log.getTopics();
String encodedEventSignature = EventEncoder.encode(event);
if (!topics.get(0).equals(encodedEventSignature)) {
return null;
}
List indexedValues = new ArrayList<>();
List nonIndexedValues = FunctionReturnDecoder.decode(
log.getData(), event.getNonIndexedParameters());
List> indexedParameters = event.getIndexedParameters();
for (int i = 0; i < indexedParameters.size(); i++) {
Type value = FunctionReturnDecoder.decodeIndexedValue(
topics.get(i + 1), indexedParameters.get(i));
indexedValues.add(value);
}
return new EventValues(indexedValues, nonIndexedValues);
}
private CompiledContract loadContract(String contractName) throws IOException {
/// TODO: jsonrpc
return new CompiledContract("");
}
/// TODO: get contract address
private String getContractAddress(String contractName) {
return "";
}
private long blockHeight() throws IOException {
return this.service.appBlockNumber().send().getBlockNumber().longValue();
}
private long getValidUntilBlock() throws IOException {
return blockHeight() + 80;
}
private String hex_remove_0x(String hex) {
if (hex.contains("0x")) {
return hex.substring(2);
}
return hex;
}
private String bytesToHexStr(byte[] byteArr) {
if (null == byteArr || byteArr.length < 1) {
return "";
}
StringBuilder sb = new StringBuilder();
for (byte t : byteArr) {
if ((t & 0xF0) == 0) {
sb.append("0");
}
sb.append(Integer.toHexString(t & 0xFF));
}
return sb.toString();
}
private byte[] hexStrToBytes(String hexStr) {
if (null == hexStr || hexStr.length() < 1) {
return null;
}
int byteLen = hexStr.length() / 2;
byte[] result = new byte[byteLen];
char[] hexChar = hexStr.toCharArray();
for (int i = 0; i < byteLen; i++) {
result[i] = (byte)
(Character.digit(hexChar[i * 2],16) << 4
| Character.digit(hexChar[i * 2 + 1],16));
}
return result;
}
}