org.ethereum.core.CallTransaction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ethereumj-core Show documentation
Show all versions of ethereumj-core Show documentation
Java implementation of the Ethereum protocol adapted to use for Hedera Smart Contract Service
The newest version!
/*
* Copyright (c) [2016] [ ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see .
*/
package org.ethereum.core;
import static java.lang.String.format;
import static org.apache.commons.lang3.ArrayUtils.subarray;
import static org.apache.commons.lang3.StringUtils.stripEnd;
import static org.ethereum.crypto.HashUtil.sha3;
import static org.ethereum.solidity.SolidityType.IntType;
import static org.ethereum.util.ByteUtil.longToBytesNoLeadZeroes;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.ethereum.solidity.SolidityType;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.FastByteComparisons;
import org.ethereum.vm.LogInfo;
import org.spongycastle.util.encoders.Hex;
/**
* Creates a contract function call transaction.
* Serializes arguments according to the function ABI .
*
* Created by Anton Nashatyrev on 25.08.2015.
*/
public class CallTransaction {
private final static ObjectMapper DEFAULT_MAPPER = new ObjectMapper()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
public static Transaction createRawTransaction(long nonce, long gasPrice, long gasLimit, String toAddress,
long value, byte[] data) {
Transaction tx = new Transaction(longToBytesNoLeadZeroes(nonce),
longToBytesNoLeadZeroes(gasPrice),
longToBytesNoLeadZeroes(gasLimit),
toAddress == null ? null : Hex.decode(toAddress),
longToBytesNoLeadZeroes(value),
data,
null);
return tx;
}
public static Transaction createCallTransaction(long nonce, long gasPrice, long gasLimit, String toAddress,
long value, Function callFunc, Object ... funcArgs) {
byte[] callData = callFunc.encode(funcArgs);
return createRawTransaction(nonce, gasPrice, gasLimit, toAddress, value, callData);
}
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Param {
public Boolean indexed;
public String name;
public SolidityType type;
@JsonGetter("type")
public String getType() {
return type.getName();
}
}
public enum StateMutabilityType {
pure,
view,
nonpayable,
payable
}
public enum FunctionType {
constructor,
function,
event,
fallback
}
public static class Function {
public boolean anonymous;
public boolean constant;
public boolean payable;
public String name = "";
public Param[] inputs = new Param[0];
public Param[] outputs = new Param[0];
public FunctionType type;
public StateMutabilityType stateMutability;
private Function() {}
public byte[] encode(Object ... args) {
return ByteUtil.merge(encodeSignature(), encodeArguments(args));
}
public byte[] encodeArguments(Object ... args) {
if (args.length > inputs.length) throw new RuntimeException("Too many arguments: " + args.length + " > " + inputs.length);
int staticSize = 0;
int dynamicCnt = 0;
// calculating static size and number of dynamic params
for (int i = 0; i < args.length; i++) {
Param param = inputs[i];
if (param.type.isDynamicType()) {
dynamicCnt++;
}
staticSize += param.type.getFixedSize();
}
byte[][] bb = new byte[args.length + dynamicCnt][];
int curDynamicPtr = staticSize;
int curDynamicCnt = 0;
for (int i = 0; i < args.length; i++) {
if (inputs[i].type.isDynamicType()) {
byte[] dynBB = inputs[i].type.encode(args[i]);
bb[i] = SolidityType.IntType.encodeInt(curDynamicPtr);
bb[args.length + curDynamicCnt] = dynBB;
curDynamicCnt++;
curDynamicPtr += dynBB.length;
} else {
bb[i] = inputs[i].type.encode(args[i]);
}
}
return ByteUtil.merge(bb);
}
private Object[] decode(byte[] encoded, Param[] params) {
Object[] ret = new Object[params.length];
int off = 0;
for (int i = 0; i < params.length; i++) {
if (params[i].type.isDynamicType()) {
ret[i] = params[i].type.decode(encoded, IntType.decodeInt(encoded, off).intValue());
} else {
ret[i] = params[i].type.decode(encoded, off);
}
off += params[i].type.getFixedSize();
}
return ret;
}
public Object[] decode(byte[] encoded) {
return decode(subarray(encoded, 4, encoded.length), inputs);
}
public Object[] decodeResult(byte[] encodedRet) {
return decode(encodedRet, outputs);
}
public String formatSignature() {
StringBuilder paramsTypes = new StringBuilder();
for (Param param : inputs) {
paramsTypes.append(param.type.getCanonicalName()).append(",");
}
return format("%s(%s)", name, stripEnd(paramsTypes.toString(), ","));
}
public byte[] encodeSignatureLong() {
String signature = formatSignature();
byte[] sha3Fingerprint = sha3(signature.getBytes());
return sha3Fingerprint;
}
public byte[] encodeSignature() {
return Arrays.copyOfRange(encodeSignatureLong(), 0, 4);
}
@Override
public String toString() {
return formatSignature();
}
public static Function fromJsonInterface(String json) {
try {
return DEFAULT_MAPPER.readValue(json, Function.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static Function fromSignature(String funcName, String ... paramTypes) {
return fromSignature(funcName, paramTypes, new String[0]);
}
public static Function fromSignature(String funcName, String[] paramTypes, String[] resultTypes) {
Function ret = new Function();
ret.name = funcName;
ret.constant = false;
ret.type = FunctionType.function;
ret.inputs = new Param[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
ret.inputs[i] = new Param();
ret.inputs[i].name = "param" + i;
ret.inputs[i].type = SolidityType.getType(paramTypes[i]);
}
ret.outputs = new Param[resultTypes.length];
for (int i = 0; i < resultTypes.length; i++) {
ret.outputs[i] = new Param();
ret.outputs[i].name = "res" + i;
ret.outputs[i].type = SolidityType.getType(resultTypes[i]);
}
return ret;
}
}
public static class Contract {
public Contract(String jsonInterface) {
try {
functions = new ObjectMapper().readValue(jsonInterface, Function[].class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Function getByName(String name) {
for (Function function : functions) {
if (name.equals(function.name)) {
return function;
}
}
return null;
}
public Function getConstructor() {
for (Function function : functions) {
if (function.type == FunctionType.constructor) {
return function;
}
}
return null;
}
private Function getBySignatureHash(byte[] hash) {
if (hash.length == 4 ) {
for (Function function : functions) {
if (FastByteComparisons.equal(function.encodeSignature(), hash)) {
return function;
}
}
} else if (hash.length == 32 ) {
for (Function function : functions) {
if (FastByteComparisons.equal(function.encodeSignatureLong(), hash)) {
return function;
}
}
} else {
throw new RuntimeException("Function signature hash should be 4 or 32 bytes length");
}
return null;
}
/**
* Parses function and its arguments from transaction invocation binary data
*/
public Invocation parseInvocation(byte[] data) {
if (data.length < 4) throw new RuntimeException("Invalid data length: " + data.length);
Function function = getBySignatureHash(Arrays.copyOfRange(data, 0, 4));
if (function == null) throw new RuntimeException("Can't find function/event by it signature");
Object[] args = function.decode(data);
return new Invocation(this, function, args);
}
/**
* Parses Solidity Event and its data members from transaction receipt LogInfo
* Finds corresponding event by its signature hash and thus is not applicable to
* anonymous events
*/
public Invocation parseEvent(LogInfo eventLog) {
CallTransaction.Function event = getBySignatureHash(eventLog.getTopics().get(0).getData());
int indexedArg = 1;
if (event == null) return null;
List