cn.hyperchain.sdk.transaction.Transaction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of litesdk Show documentation
Show all versions of litesdk Show documentation
A Java client tool for Hyperchain
package cn.hyperchain.sdk.transaction;
import cn.hyperchain.contract.BaseInvoke;
import cn.hyperchain.sdk.account.Account;
import cn.hyperchain.sdk.account.DIDAccount;
import cn.hyperchain.sdk.bvm.operate.BuiltinOperation;
import cn.hyperchain.sdk.common.solidity.Abi;
import cn.hyperchain.sdk.common.solidity.ContractType;
import cn.hyperchain.sdk.common.utils.Encoder;
import cn.hyperchain.sdk.common.utils.FuncParams;
import cn.hyperchain.sdk.common.utils.InvokeDirectlyParams;
import cn.hyperchain.sdk.common.utils.InvokeHVMAbiParams;
import cn.hyperchain.sdk.common.utils.ByteUtil;
import cn.hyperchain.sdk.common.utils.MethodNameUtil;
import cn.hyperchain.sdk.common.utils.Utils;
import cn.hyperchain.sdk.crypto.HashUtil;
import cn.hyperchain.sdk.did.DIDCredential;
import cn.hyperchain.sdk.did.DIDDocument;
import cn.hyperchain.sdk.did.DIDPublicKey;
import cn.hyperchain.sdk.transaction.proto.TransactionValueProto;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.protobuf.ByteString;
import org.bouncycastle.util.encoders.Hex;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Transaction {
private Transaction() {
}
private static final Gson gson = new GsonBuilder().disableHtmlEscaping()
.registerTypeAdapter(Transaction.class, new TxDeserializer()).create();
public static final long DEFAULT_GAS_LIMIT = 1000000000;
public static final long DEFAULT_GAS_LIMIT_FLATO = 10000000;
private static final int EXTRAID_STRING_MAX_LENGTH = 1024;
private static final int EXTRAID_LIST_MAX_LENGTH = 30;
// maintain opcode const
private static final int UPDATE = 1;
private static final int FREEZE = 2;
private static final int UNFREEZE = 3;
private static final int DESTROY = 5;
private static final int DID_REGISTER = 200;
private static final int DID_FREEZE = 201;
private static final int DID_UNFREEZE = 202;
private static final int DID_ABANDON = 203;
private static final int DID_UPDATEPUBLICKEY = 204;
private static final int DID_UPDATEADMINS = 205;
private static final int DIDCREDENTIAL_UPLOAD = 206;
private static final int DIDCREDENTIAL_DOWNLOAD = 207;
private static final int DIDCREDENTIAL_ABANDON = 208;
private static final int DID_SETEXTRA = 209;
private static final int DID_GETEXTRA = 210;
private Account account;
private String from;
private String to;
private String payload = "";
private long value = 0;
private boolean simulate;
private VMType vmType;
private int opCode;
private String extra = "";
private long timestamp;
private long nonce;
private ArrayList extraIdLong;
private ArrayList extraIdString;
private String signature = "";
private String needHashString;
private String contractName = "";
private TxVersion txVersion = TxVersion.GLOBAL_TX_VERSION;
public static class Builder {
Transaction transaction;
/**
* create transfer or generate transaction.
*
* @param from account address
*/
public Builder(String from) {
transaction = new Transaction();
transaction.setFrom(from);
transaction.setVmType(VMType.EVM);
}
/**
* create a transform transaction from account A to account B.
*
* @param to origin account
* @param value goal account
* @return {@link Builder}
*/
public Builder transfer(String to, long value) {
transaction.setTo(to);
transaction.setValue(value);
transaction.setVmType(VMType.TRANSFER);
return this;
}
/**
* make transaction status is simulate.
*
* @return {@link Builder}
*/
public Builder simulate() {
transaction.setSimulate(true);
return this;
}
/**
* set tx version(must corresponding to flato version).
*
* @param txVersion tx version
* @return {@link Builder}
*/
public Builder txVersion(TxVersion txVersion) {
transaction.setTxVersion(txVersion);
return this;
}
/**
* add transaction extra info.
*
* @param extra extra data
* @return {@link Builder}
*/
public Builder extra(String extra) {
transaction.setExtra(extra);
return this;
}
/**
* set transaction extraIDLong.
*
* @param extraIDLong extraID long
* @return {@link Builder}
*/
public Builder extraIDLong(Long... extraIDLong) {
transaction.setExtraIDLong(extraIDLong);
return this;
}
/**
* add transaction extraIDLong.
*
* @param extraIDLong extraID long
* @return {@link Builder}
*/
public Builder addExtraIDLong(Long... extraIDLong) {
transaction.addExtraIDLong(extraIDLong);
return this;
}
/**
* set transaction extraIDString.
*
* @param extraIDString extraID String
* @return {@link Builder}
*/
public Builder extraIDString(String... extraIDString) {
transaction.setExtraIdString(extraIDString);
return this;
}
/**
* add transaction extraIDString.
*
* @param extraIDString extraID String
* @return {@link Builder}
*/
public Builder addExtraIDString(String... extraIDString) {
transaction.addExtraIdString(extraIDString);
return this;
}
/**
* upgrade contract.
*
* @param contractAddress contract address in chain
* @param payload payload of the new contract
* @return {@link Builder}
*/
public Builder upgrade(String contractAddress, String payload) {
transaction.setPayload(payload);
transaction.setTo(contractAddress);
transaction.setOpCode(UPDATE);
return this;
}
/**
* set contract name.
*
* @param contractName contract name in chain
* @return {@link Builder}
*/
public Builder contractName(String contractName) {
transaction.setContractName(contractName);
transaction.setTo("0x0000000000000000000000000000000000000000");
return this;
}
/**
* freeze contract.
*
* @param contractAddress contract address in chain
* @return {@link Builder}
*/
public Builder freeze(String contractAddress) {
transaction.setOpCode(FREEZE);
transaction.setTo(contractAddress);
return this;
}
/**
* unfreeze contract.
*
* @param contractAddress contract address in chain
* @return {@link Builder}
*/
public Builder unfreeze(String contractAddress) {
transaction.setTo(contractAddress);
transaction.setOpCode(UNFREEZE);
return this;
}
/**
* destroy contract.
*
* @param contractAddress contract address in chain
* @return {@link Builder}
*/
public Builder destroy(String contractAddress) {
transaction.setTo(contractAddress);
transaction.setOpCode(DESTROY);
return this;
}
/**
* set transaction vm type.
*
* @param vmType {@link VMType}
* @return this
*/
public Builder vmType(VMType vmType) {
transaction.setVmType(vmType);
return this;
}
/**
* set invoke contract address.
*
* @param contractAddress contract address in chain
* @param isDID didAccount
* @return {@link Builder}
*/
protected Builder invokeContractAddr(String contractAddress, boolean isDID, String chainID) {
if (isDID) {
String didContractAddress = DIDAccount.DID_PREFIX + chainID + ":" + contractAddress;
transaction.setTo(didContractAddress);
} else {
transaction.setTo(contractAddress);
}
return this;
}
/**
* build transaction instance.
*
* @return {@link Transaction}
*/
public Transaction build() {
transaction.setTimestamp(genTimestamp());
transaction.setNonce(genNonce());
return transaction;
}
}
public static class HVMBuilder extends Builder {
public HVMBuilder(String from) {
super(from);
super.transaction.setVmType(VMType.HVM);
}
/**
* create deployment transaction for {@link VMType} HVM.
*
* @param fis FileInputStream for the given jar file
* @return {@link Builder}
*/
public Builder deploy(InputStream fis) {
String payload = Encoder.encodeDeployJar(fis, transaction.txVersion);
super.transaction.setTo("0x0");
super.transaction.setPayload(payload);
return this;
}
/**
* upgrade hvm contract.
* @param contractAddress contract address in chain
* @param fis FileInputStream for the given jar file
* @return {@link Builder}
*/
public Builder upgrade(String contractAddress, InputStream fis) {
transaction.setPayload(Encoder.encodeDeployJar(fis, transaction.txVersion));
transaction.setTo(contractAddress);
transaction.setOpCode(UPDATE);
return this;
}
/**
* create invoking transaction for {@link VMType} HVM.
*
* @param contractAddress contract address in chain
* @param baseInvoke an instance of {@link BaseInvoke}
* @return {@link Builder}
*/
public Builder invoke(String contractAddress, BaseInvoke baseInvoke) {
return invoke(contractAddress, baseInvoke, false, null);
}
/**
* create invoking transaction for {@link VMType} HVM.
*
* @param contractAddress contract address in chain
* @param baseInvoke an instance of {@link BaseInvoke}
* @param isDID didAccount invoke
* @return {@link Builder}
*/
public Builder invoke(String contractAddress, BaseInvoke baseInvoke, boolean isDID, String chainID) {
String payload = Encoder.encodeInvokeBeanJava(baseInvoke);
super.transaction.setPayload(payload);
return invokeContractAddr(contractAddress, isDID, chainID);
}
/**
* create invoking transaction for {@link VMType} HVM.
*
* @param contractAddress contract address in chain
* @param invokeDirectlyParams params of directly invoking contract
* @return {@link Builder}
*/
public Builder invokeDirectly(String contractAddress, InvokeDirectlyParams invokeDirectlyParams) {
return invokeDirectly(contractAddress, invokeDirectlyParams, false, null);
}
/**
* create invoking transaction for {@link VMType} HVM.
*
* @param contractAddress contract address in chain
* @param invokeDirectlyParams params of directly invoking contract
* @param isDID didAccount invoke
* @return {@link Builder}
*/
public Builder invokeDirectly(String contractAddress, InvokeDirectlyParams invokeDirectlyParams, boolean isDID, String chainID) {
String payload = invokeDirectlyParams.getParams();
super.transaction.setPayload(payload);
return invokeContractAddr(contractAddress, isDID, chainID);
}
/**
* create invoking transaction for {@link VMType} HVM.
*
* @param contractAddress contract address in chain
* @param hvmAbiParams params of invoking contract by invoke bean
* @return {@link Builder}
*/
public Builder invokeByBeanAbi(String contractAddress, InvokeHVMAbiParams hvmAbiParams) {
String payload = hvmAbiParams.getParams();
super.transaction.setPayload(payload);
return invokeContractAddr(contractAddress, false, null);
}
}
public static class EVMBuilder extends Builder {
public EVMBuilder(String from) {
super(from);
super.transaction.setVmType(VMType.EVM);
}
/**
* deploy Solidity contract bin.
*
* @param bin contract bin
* @return {@link Builder}
*/
public Builder deploy(String bin) {
super.transaction.setTo("0x0");
super.transaction.setPayload(bin);
return this;
}
/**
* deploy Solidity contract bin with params.
*
* @param bin contract bin
* @param abi contract abi
* @param params deploy contract params
* @return {@link Builder}
*/
public Builder deploy(String bin, Abi abi, FuncParams params) {
super.transaction.setTo("0x0");
String payload = bin + ByteUtil.toHex(abi.getConstructor().encode(params.getParams()));
super.transaction.setPayload(payload);
return this;
}
/**
* invoke Solidity contract whit specific method and params.
*
* @param methodName method name
* @param abi contract abi
* @param params invoke params
* @return {@link Builder}
*/
public Builder invoke(String contractAddress, String methodName, Abi abi, FuncParams params) {
return invoke(contractAddress, methodName, abi, params, false, null);
}
/**
* invoke Solidity contract whit specific method and params.
* @param contractAddress contract address in chain
* @param methodName method name
* @param abi contract abi
* @param params invoke params
* @param isDID didAccount invoke
* @return {@link Builder}
*/
public Builder invoke(String contractAddress, String methodName, Abi abi, FuncParams params, boolean isDID, String chainID) {
methodName = MethodNameUtil.getNormalizedMethodName(methodName);
ContractType.Function abiFunction = abi.getFunction(methodName);
if (abiFunction == null) {
throw new NullPointerException("Evm method name error, so we can't find method " + methodName + ", please check the document at https://github.com/hyperchain/javasdk/tree/master/docs!");
}
String payload = ByteUtil.toHex(abiFunction.encode(params.getParams()));
super.transaction.setPayload(payload);
return invokeContractAddr(contractAddress, isDID, chainID);
}
/**
* create a transform transaction from account A to account B.
*
* @param to origin account
* @param value goal account
* @return {@link Builder}
*/
@Override
public Builder transfer(String to, long value) {
transaction.setTo(to);
transaction.setValue(value);
return this;
}
}
public static class BVMBuilder extends Builder {
public BVMBuilder(String from) {
super(from);
super.transaction.setVmType(VMType.BVM);
}
/**
* invoke BVM contract whit specific method and params.
*
* @param contractAddress contract address
* @param methodName method name
* @param params invoke params
* @return {@link Builder}
*/
@Deprecated
public Builder invoke(String contractAddress, String methodName, String... params) {
super.transaction.setTo(contractAddress);
String payload = Encoder.encodeBVM(methodName, params);
super.transaction.setPayload(payload);
return this;
}
/**
* invoke BVM contract for builtin operation.
*
* @param opt operation
* @return {@link Builder}
*/
public Builder invoke(BuiltinOperation opt) {
return invoke(opt, false, null);
}
/**
* invoke BVM contract for builtin operation.
* @param opt operation
* @param isDID didAccount invoke
* @return {@link Builder}
*/
public Builder invoke(BuiltinOperation opt, boolean isDID, String chainID) {
super.transaction.setPayload(ByteUtil.toHex(Encoder.encodeOperation(opt)));
return invokeContractAddr(opt.getAddress(), isDID, chainID);
}
}
public static class DIDBuilder extends Builder {
public DIDBuilder(String from) {
super(from);
super.transaction.setVmType(VMType.TRANSFER);
}
/**
* register a didAccount.
* @param didDocument represent a didAccount
* @return {@link Builder}
*/
public Builder create(DIDDocument didDocument) {
super.transaction.setTo(super.transaction.getFrom());
String param = gson.toJson(didDocument);
super.transaction.setPayload(ByteUtil.toHex(param.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setOpCode(DID_REGISTER);
return this;
}
/**
* freeze a didAccount.
* @param to didAddress to be freezed
* @return {@link Builder}
*/
@Override
public Builder freeze(String to) {
super.transaction.setOpCode(DID_FREEZE);
super.transaction.setTo(to);
return this;
}
/**
* unfreeze a didAccount.
* @param to didAddress
* @return {@link Builder}
*/
@Override
public Builder unfreeze(String to) {
super.transaction.setOpCode(DID_UNFREEZE);
super.transaction.setTo(to);
return this;
}
/**
* destroy a didAccount.
* @param to didAddress
* @return {@link Builder}
*/
@Override
public Builder destroy(String to) {
super.transaction.setOpCode(DID_ABANDON);
super.transaction.setTo(to);
return this;
}
/**
* update the publicKey of didAccount.
* @param to didAddress
* @param publickey publickey
* @return {@link Builder}
*/
public Builder updatePublicKey(String to, DIDPublicKey publickey) {
String param = gson.toJson(publickey);
super.transaction.setPayload(ByteUtil.toHex(param.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setTo(to);
super.transaction.setOpCode(DID_UPDATEPUBLICKEY);
return this;
}
/**
* update the admins of didAccount.
* @param to didAddress
* @param admins admins
* @return {@link Builder}
*/
public Builder updateAdmins(String to, String[] admins) {
String param = gson.toJson(admins);
super.transaction.setPayload(ByteUtil.toHex(param.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setTo(to);
super.transaction.setOpCode(DID_UPDATEADMINS);
return this;
}
/**
* upload credential.
* @param credential credential
* @return {@link Builder}
*/
public Builder uploadCredential(DIDCredential credential) {
super.transaction.setTo(super.transaction.getFrom());
String param = gson.toJson(credential);
super.transaction.setPayload(ByteUtil.toHex(param.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setOpCode(DIDCREDENTIAL_UPLOAD);
return this;
}
/**
* download a credential.
* @param credentialID the id of credential
* @return {@link Builder}
*/
public Builder downloadCredential(String credentialID) {
super.transaction.setTo(super.transaction.getFrom());
super.transaction.setPayload(ByteUtil.toHex(credentialID.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setOpCode(DIDCREDENTIAL_DOWNLOAD);
return this;
}
/**
* destroy a credential.
* @param credentialID the id of credential
* @return {@link Builder}
*/
public Builder destroyCredential(String credentialID) {
super.transaction.setTo(super.transaction.getFrom());
super.transaction.setPayload(ByteUtil.toHex(credentialID.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setOpCode(DIDCREDENTIAL_ABANDON);
return this;
}
/**
* set did extra.
* @param to target
* @param key -
* @param value -
* @return {@link Builder}
*/
public Builder setExtra(String to, String key, String value) {
super.transaction.setTo(to);
Map map = new HashMap(2);
map.put("key", key);
map.put("value", value);
String param = gson.toJson(map);
super.transaction.setPayload(ByteUtil.toHex(param.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setOpCode(DID_SETEXTRA);
return this;
}
/**
* get did extra.
* @param to target
* @param key -
* @return {@link Builder}
*/
public Builder getExtra(String to, String key) {
super.transaction.setTo(to);
Map map = new HashMap(1);
map.put("key", key);
String param = gson.toJson(map);
super.transaction.setPayload(ByteUtil.toHex(param.getBytes(Utils.DEFAULT_CHARSET)));
super.transaction.setOpCode(DID_GETEXTRA);
return this;
}
}
public static class SQLBuilder extends Builder {
// default invoke kvsql use rawsql
public static final byte rawSql = 0;
/**
* create transfer or generate transaction.
* @param from account address
*/
public SQLBuilder(String from) {
super(from);
super.transaction.setVmType(VMType.KVSQL);
}
/**
* invoke sql.
* @param to database address
* @param sql sql text
* @return {@link Builder}
*/
public Builder invoke(String to, String sql) {
this.transaction.setTo(to);
byte[] data = ByteUtil.merge(new byte[]{rawSql}, sql.getBytes(Charset.defaultCharset()));
this.transaction.setPayload(ByteUtil.toHex(data));
return this;
}
/**
* create a kvsql database.
* @return {@link Builder}
*/
public Builder create() {
this.transaction.setTo("0x0");
//KVSQL
this.transaction.setPayload("0x4b5653514c");
return this;
}
}
/**
* setNeedHashString.
*/
public void setNeedHashString() {
// flato
if (txVersion.isGreaterOrEqual(TxVersion.TxVersion20)) {
String payload = Utils.isBlank(this.payload) ? "0x0" : chPrefix(this.payload.toLowerCase());
this.needHashString = "from=" + chPrefix(from.toLowerCase())
+ "&to=" + chPrefix(to.toLowerCase())
+ "&value=" + chPrefix(Long.toHexString(this.value))
+ "&payload=" + payload
+ "×tamp=0x" + Long.toHexString(this.timestamp)
+ "&nonce=0x" + Long.toHexString(this.nonce)
+ "&opcode=" + Integer.toHexString(this.opCode)
+ "&extra=" + this.extra
+ "&vmtype=" + this.vmType.getType()
+ "&version=" + this.txVersion.getVersion();
if (txVersion.isGreaterOrEqual(TxVersion.TxVersion21)) {
this.needHashString += "&extraid=" + this.buildExtraID();
}
if (txVersion.isGreaterOrEqual(TxVersion.TxVersion22)) {
this.needHashString += "&cname=" + this.contractName;
}
} else { // hyperchain
String value = Utils.isBlank(this.payload) ? Long.toHexString(this.value) : this.payload;
this.needHashString = "from=" + chPrefix(this.from.toLowerCase())
+ "&to=" + chPrefix(this.to.toLowerCase())
+ "&value=" + chPrefix(value)
+ "×tamp=0x" + Long.toHexString(this.timestamp)
+ "&nonce=0x" + Long.toHexString(this.nonce)
+ "&opcode=" + this.opCode
+ "&extra=" + this.extra
+ "&vmtype=" + this.vmType.getType();
}
}
/**
* create transaction signature.
*
* @param account sign account
*/
public void sign(Account account) {
this.account = account;
this.setNeedHashString();
byte[] sourceData = this.needHashString.getBytes(Utils.DEFAULT_CHARSET);
this.signature = ByteUtil.toHex(account.sign(sourceData));
}
private static String chPrefix(String origin) {
return origin.startsWith("0x") ? origin : "0x" + origin;
}
private static Long genNonce() {
return Utils.genNonce();
}
private static Long genTimestamp() {
return System.currentTimeMillis() * 1000000 + Utils.randInt(1000, 1000000);
}
public String getFrom() {
return from;
}
/**
* set the transaction from address, hex coding.
*
* @param from address
*/
public void setFrom(String from) {
if (from != null && from.startsWith(DIDAccount.DID_PREFIX)) {
from = ByteUtil.toHex(from.getBytes(Utils.DEFAULT_CHARSET));
}
this.from = from;
}
public String getTo() {
return to;
}
/**
* set the transaction to address, hex coding.
*
* @param to address
*/
public void setTo(String to) {
if (to != null && to.startsWith(DIDAccount.DID_PREFIX)) {
to = ByteUtil.toHex(to.getBytes(Utils.DEFAULT_CHARSET));
}
this.to = to;
}
public String getContractName() {
return contractName;
}
public void setContractName(String contractName) {
this.contractName = contractName;
}
public String getPayload() {
return payload;
}
public void setPayload(String payload) {
this.payload = chPrefix(payload);
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
public boolean isSimulate() {
return simulate;
}
public void setSimulate(boolean simulate) {
this.simulate = simulate;
}
public VMType getVmType() {
return vmType;
}
public void setVmType(VMType vmType) {
this.vmType = vmType;
}
public int getOpCode() {
return opCode;
}
public void setOpCode(int opCode) {
this.opCode = opCode;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public long getNonce() {
return nonce;
}
public void setNonce(long nonce) {
this.nonce = nonce;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getNeedHashString() {
return needHashString;
}
public TxVersion getTxVersion() {
return txVersion;
}
public Account getAccount() {
return account;
}
public void setTxVersion(TxVersion txVersion) {
this.txVersion = txVersion;
}
private String buildExtraID() {
ArrayList
© 2015 - 2024 Weber Informatics LLC | Privacy Policy