@@ -13,12 +13,14 @@ import com.jd.blockchain.contract.ContractEvent; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.runtime.Module; | |||
import com.jd.blockchain.transaction.ContractType; | |||
import com.jd.blockchain.utils.BaseConstant; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* contract code based jvm | |||
* @author zhaogw | |||
* | |||
* @author zhaogw | |||
*/ | |||
public class JavaContractCode implements ContractCode { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); | |||
@@ -26,7 +28,9 @@ public class JavaContractCode implements ContractCode { | |||
private Bytes address; | |||
private long version; | |||
private ContractEventContext contractEventContext; | |||
private ContractType contractType; | |||
public JavaContractCode(Bytes address, long version, Module codeModule) { | |||
this.address = address; | |||
this.version = version; | |||
@@ -37,7 +41,7 @@ public class JavaContractCode implements ContractCode { | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public long getVersion() { | |||
return version; | |||
@@ -46,35 +50,45 @@ public class JavaContractCode implements ContractCode { | |||
@Override | |||
public void processEvent(ContractEventContext eventContext) { | |||
this.contractEventContext = eventContext; | |||
codeModule.execute(new ContractThread()); | |||
codeModule.execute(new ContractExecution()); | |||
} | |||
class ContractThread implements Runnable{ | |||
public void run(){ | |||
private Object[] resolveArgs(byte[] args) { | |||
// TODO Auto-generated method stub | |||
return null; | |||
} | |||
class ContractExecution implements Runnable { | |||
public void run() { | |||
LOGGER.info("ContractThread execute()."); | |||
try { | |||
//执行预处理; | |||
// 执行预处理; | |||
long startTime = System.currentTimeMillis(); | |||
String contractClassName = codeModule.getMainClass(); | |||
Class myClass = codeModule.loadClass(contractClassName); | |||
Object contractMainClassObj = myClass.newInstance();//合约主类生成的类实例; | |||
Object contractMainClassObj = myClass.newInstance();// 合约主类生成的类实例; | |||
Method beforeMth_ = myClass.getMethod("beforeEvent",codeModule.loadClass(ContractEventContext.class.getName())); | |||
ReflectionUtils.invokeMethod(beforeMth_,contractMainClassObj,contractEventContext); | |||
LOGGER.info("beforeEvent,耗时:"+(System.currentTimeMillis()-startTime)); | |||
Method beforeMth_ = myClass.getMethod("beforeEvent", | |||
codeModule.loadClass(ContractEventContext.class.getName())); | |||
ReflectionUtils.invokeMethod(beforeMth_, contractMainClassObj, contractEventContext); | |||
LOGGER.info("beforeEvent,耗时:" + (System.currentTimeMillis() - startTime)); | |||
Method eventMethod = this.getMethodByAnno(contractMainClassObj,contractEventContext.getEvent()); | |||
Method eventMethod = this.getMethodByAnno(contractMainClassObj, contractEventContext.getEvent()); | |||
startTime = System.currentTimeMillis(); | |||
ReflectionUtils.invokeMethod(eventMethod,contractMainClassObj,contractEventContext); | |||
// 反序列化参数; | |||
Method handleMethod = contractType.getHandleMethod(contractEventContext.getEvent()); | |||
Object[] args = resolveArgs(contractEventContext.getArgs()); | |||
ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, args); | |||
LOGGER.info("合约执行,耗时:"+(System.currentTimeMillis()-startTime)); | |||
LOGGER.info("合约执行,耗时:" + (System.currentTimeMillis() - startTime)); | |||
Method mth2 = myClass.getMethod("postEvent"); | |||
startTime = System.currentTimeMillis(); | |||
ReflectionUtils.invokeMethod(mth2,contractMainClassObj); | |||
LOGGER.info("postEvent,耗时:"+(System.currentTimeMillis()-startTime)); | |||
ReflectionUtils.invokeMethod(mth2, contractMainClassObj); | |||
LOGGER.info("postEvent,耗时:" + (System.currentTimeMillis() - startTime)); | |||
} catch (NoSuchMethodException e) { | |||
e.printStackTrace(); | |||
} catch (Exception e) { | |||
@@ -82,39 +96,41 @@ public class JavaContractCode implements ContractCode { | |||
} | |||
} | |||
//得到当前类中相关方法和注解对应关系; | |||
Method getMethodByAnno(Object classObj, String eventName){ | |||
// 得到当前类中相关方法和注解对应关系; | |||
Method getMethodByAnno(Object classObj, String eventName) { | |||
Class<?> c = classObj.getClass(); | |||
Class <ContractEvent> contractEventClass = null; | |||
Class<ContractEvent> contractEventClass = null; | |||
try { | |||
contractEventClass = (Class <ContractEvent>)c.getClassLoader().loadClass(ContractEvent.class.getName()); | |||
contractEventClass = (Class<ContractEvent>) c.getClassLoader().loadClass(ContractEvent.class.getName()); | |||
} catch (ClassNotFoundException e) { | |||
e.printStackTrace(); | |||
} | |||
Method[] classMethods = c.getMethods(); | |||
Map<Method, Annotation[]> methodAnnoMap = new HashMap<Method, Annotation[]>(); | |||
Map<String,Method> annoMethodMap = new HashMap<String,Method>(); | |||
for(int i = 0;i<classMethods.length;i++){ | |||
Map<String, Method> annoMethodMap = new HashMap<String, Method>(); | |||
for (int i = 0; i < classMethods.length; i++) { | |||
Annotation[] a = classMethods[i].getDeclaredAnnotations(); | |||
methodAnnoMap.put(classMethods[i], a); | |||
//如果当前方法中包含@ContractEvent注解,则将其放入Map; | |||
for(Annotation annotation_ : a){ | |||
//如果是合同事件类型,则放入map; | |||
if(classMethods[i].isAnnotationPresent(contractEventClass)){ | |||
// 如果当前方法中包含@ContractEvent注解,则将其放入Map; | |||
for (Annotation annotation_ : a) { | |||
// 如果是合同事件类型,则放入map; | |||
if (classMethods[i].isAnnotationPresent(contractEventClass)) { | |||
Object obj = classMethods[i].getAnnotation(contractEventClass); | |||
String annoAllName = obj.toString(); | |||
//format:@com.jd.blockchain.contract.model.ContractEvent(name=transfer-asset) | |||
String eventName_ = obj.toString().substring(BaseConstant.CONTRACT_EVENT_PREFIX.length(),annoAllName.length()-1); | |||
annoMethodMap.put(eventName_,classMethods[i]); | |||
// format:@com.jd.blockchain.contract.model.ContractEvent(name=transfer-asset) | |||
String eventName_ = obj.toString().substring(BaseConstant.CONTRACT_EVENT_PREFIX.length(), | |||
annoAllName.length() - 1); | |||
annoMethodMap.put(eventName_, classMethods[i]); | |||
break; | |||
} | |||
} | |||
} | |||
if(annoMethodMap.containsKey(eventName)){ | |||
if (annoMethodMap.containsKey(eventName)) { | |||
return annoMethodMap.get(eventName); | |||
}else { | |||
} else { | |||
return null; | |||
} | |||
} | |||
} | |||
} |
@@ -43,22 +43,22 @@ public class LedgerTestUtils { | |||
return txHandle.txRequest; | |||
} | |||
public static TransactionRequest createContractEventTxRequest(HashDigest ledgerHash, | |||
SignatureFunction signatureFunction, String contractAddress, String event, byte[] args) { | |||
TxHandle txHandle = new TxHandle(); | |||
TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle); | |||
txTemp.contractEvents().send(contractAddress, event, args); | |||
AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); | |||
PubKey pubKey = cryptoKeyPair.getPubKey(); | |||
txTemp.users().register(new BlockchainIdentityData(pubKey)); | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
ptx.sign(cryptoKeyPair); | |||
ptx.commit(); | |||
return txHandle.txRequest; | |||
} | |||
// public static TransactionRequest createContractEventTxRequest(HashDigest ledgerHash, | |||
// SignatureFunction signatureFunction, String contractAddress, String event, byte[] args) { | |||
// TxHandle txHandle = new TxHandle(); | |||
// | |||
// TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle); | |||
// | |||
// txTemp.contractEvents().send(contractAddress, event, args); | |||
// | |||
// AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); | |||
// PubKey pubKey = cryptoKeyPair.getPubKey(); | |||
// txTemp.users().register(new BlockchainIdentityData(pubKey)); | |||
// PreparedTransaction ptx = txTemp.prepare(); | |||
// ptx.sign(cryptoKeyPair); | |||
// ptx.commit(); | |||
// return txHandle.txRequest; | |||
// } | |||
public static TransactionStagedSnapshot generateRandomSnapshot() { | |||
TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot(); | |||
@@ -6,14 +6,12 @@ import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertTrue; | |||
import java.security.KeyFactory; | |||
import java.util.Random; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
@@ -25,7 +23,6 @@ import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.TransactionBuilder; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
@@ -62,7 +59,7 @@ public class TransactionSetTest { | |||
// Build transaction request; | |||
HashDigest ledgerHash = LedgerTestUtils.generateRandomHash(); | |||
TransactionBuilder txBuilder = new TxBuilder(ledgerHash); | |||
TxBuilder txBuilder = new TxBuilder(ledgerHash); | |||
BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); | |||
UserRegisterOperation userRegOp = txBuilder.users().register(userKey.getIdentity()); | |||
@@ -74,7 +74,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||
return contractCodeDeployOpBuilder; | |||
} | |||
@Override | |||
public ContractEventSendOperationBuilder contractEvents() { | |||
return contractEventSendOpBuilder; | |||
} | |||
@@ -3,19 +3,46 @@ package com.jd.blockchain.transaction; | |||
import java.lang.reflect.InvocationHandler; | |||
import java.lang.reflect.Method; | |||
public class ContractInvocationProxy implements InvocationHandler { | |||
private String contractMessage; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractInvocationProxy implements InvocationHandler { | |||
// private String contractMessage; | |||
private Bytes contractAddress; | |||
private ContractType contractType; | |||
private ContractEventSendOperationBuilder sendOpBuilder; | |||
public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, | |||
ContractEventSendOperationBuilder sendOpBuilder) { | |||
this.contractAddress = contractAddress; | |||
this.contractType = contractType; | |||
this.sendOpBuilder = sendOpBuilder; | |||
} | |||
@Override | |||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |||
// TODO Auto-generated method stub | |||
String event = contractType.getEvent(method); | |||
if (event == null) { | |||
// 适配 Object 对象的方法; | |||
// toString 方法; | |||
return String.format("[%s]-%s", contractAddress, contractType.toString()); | |||
// hashCode 方法; | |||
} | |||
// 合约方法; | |||
byte[] argBytes = serializeArgs(args); | |||
sendOpBuilder.send(contractAddress, event, argBytes); | |||
// TODO: 暂时未考虑有返回值的情况; | |||
return null; | |||
} | |||
private byte[] serializeArgs(Object[] args) { | |||
// TODO 根据方法参数的定义序列化参数; | |||
return null; | |||
} | |||
@@ -1,6 +1,45 @@ | |||
package com.jd.blockchain.transaction; | |||
class ContractInvocationProxyBuilder { | |||
import java.lang.reflect.Proxy; | |||
import java.util.Map; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractInvocationProxyBuilder { | |||
private Map<Class<?>, ContractType> contractTypes; | |||
public <T> T create(String address, Class<T> contractIntf, BlockchainOperationFactory opFactory) { | |||
return create(Bytes.fromBase58(address), contractIntf, opFactory); | |||
} | |||
@SuppressWarnings("unchecked") | |||
public <T> T create(Bytes address, Class<T> contractIntf, BlockchainOperationFactory opFactory) { | |||
ContractType contractType = resolveContractType(contractIntf); | |||
ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, | |||
opFactory.contractEvents()); | |||
T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), | |||
new Class<?>[] { contractIntf }, proxyHandler); | |||
return (T) proxy; | |||
} | |||
private ContractType resolveContractType(Class<?> contractIntf) { | |||
ContractType contractType = contractTypes.get(contractIntf); | |||
if (contractType != null) { | |||
return contractType; | |||
} | |||
// 判断是否是标注了合约的接口类型; | |||
// 解析合约事件处理方法,检查是否有重名; | |||
// TODO 检查是否不支持的参数类型; | |||
// TODO 检查返回值类型; | |||
return null; | |||
} | |||
} |
@@ -4,12 +4,12 @@ import java.lang.reflect.Method; | |||
import java.util.Set; | |||
import java.util.SortedMap; | |||
class ContractType { | |||
public class ContractType { | |||
private String name; | |||
private SortedMap<String, Method> events; | |||
private SortedMap<Method, String> handleMethods; | |||
/** | |||
@@ -17,7 +17,7 @@ class ContractType { | |||
* | |||
* @return | |||
*/ | |||
Set<String> getEvents() { | |||
public Set<String> getEvents() { | |||
return events.keySet(); | |||
} | |||
@@ -29,7 +29,7 @@ class ContractType { | |||
* @param method | |||
* @return | |||
*/ | |||
String getEvent(Method method) { | |||
public String getEvent(Method method) { | |||
return handleMethods.get(method); | |||
} | |||
@@ -41,16 +41,15 @@ class ContractType { | |||
* @param event | |||
* @return | |||
*/ | |||
Method getHandleMethod(String event) { | |||
public Method getHandleMethod(String event) { | |||
return events.get(event); | |||
} | |||
private ContractType() { | |||
} | |||
// public static ContractType resolve(Class<?> contractIntf) { | |||
// | |||
// } | |||
// public static ContractType resolve(Class<?> contractIntf) { | |||
// | |||
// } | |||
} |
@@ -1,14 +1,25 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface EventOperator { | |||
// /** | |||
// * 合约事件; | |||
// * | |||
// * @return | |||
// */ | |||
// @Deprecated | |||
// ContractEventSendOperationBuilder contractEvents(); | |||
/** | |||
* 部署合约; | |||
* 创建调用合约的代理实例; | |||
* | |||
* @param address | |||
* @param contractIntf | |||
* @return | |||
*/ | |||
@Deprecated | |||
ContractEventSendOperationBuilder contractEvents(); | |||
<T> T contract(String address, Class<T> contractIntf); | |||
/** | |||
* 创建调用合约的代理实例; | |||
@@ -17,6 +28,6 @@ public interface EventOperator { | |||
* @param contractIntf | |||
* @return | |||
*/ | |||
<T> T contract(String address, Class<T> contractIntf); | |||
<T> T contract(Bytes address, Class<T> contractIntf); | |||
} |
@@ -21,6 +21,8 @@ public class TxBuilder implements TransactionBuilder { | |||
private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; | |||
private HashDigest ledgerHash; | |||
private ContractInvocationProxyBuilder contractInvoProxyBuilder; | |||
public TxBuilder(HashDigest ledgerHash) { | |||
this.ledgerHash = ledgerHash; | |||
@@ -79,15 +81,18 @@ public class TxBuilder implements TransactionBuilder { | |||
return opFactory.contracts(); | |||
} | |||
@Override | |||
public ContractEventSendOperationBuilder contractEvents() { | |||
return opFactory.contractEvents(); | |||
} | |||
@Override | |||
public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
return contractInvoProxyBuilder.create(address, contractIntf, opFactory); | |||
} | |||
@Override | |||
public <T> T contract(String address, Class<T> contractIntf) { | |||
// TODO Auto-generated method stub | |||
throw new IllegalStateException("Not implemented."); | |||
return contractInvoProxyBuilder.create(address, contractIntf, opFactory); | |||
} | |||
} |
@@ -53,10 +53,10 @@ public class TxTemplate implements TransactionTemplate { | |||
return txBuilder.contracts(); | |||
} | |||
@Override | |||
public ContractEventSendOperationBuilder contractEvents() { | |||
return txBuilder.contractEvents(); | |||
} | |||
// @Override | |||
// public ContractEventSendOperationBuilder contractEvents() { | |||
// return txBuilder.contractEvents(); | |||
// } | |||
@Override | |||
public <T> T contract(String address, Class<T> contractIntf) { | |||
@@ -4,8 +4,6 @@ import com.jd.blockchain.consensus.service.NodeServer; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.tools.initializer.LedgerBindingConfig; | |||
import java.util.List; | |||
public interface LedgerBindingConfigAware { | |||
void setConfig(LedgerBindingConfig config); | |||
@@ -68,9 +68,12 @@ public class SDKDemo_Contract { | |||
Remark remark = new Remark(); | |||
String remarkJSON = JSONSerializeUtils.serializeToJSON(remark); | |||
// AssetContract assetContract = txTemp.contract("", AssetContract.class); | |||
// txTemp.contractInvocation(assetContract.issue(amount, assetHolderAddress)) | |||
AssetContract assetContract = txTemp.contract(profitDistributionContract, AssetContract.class); | |||
assetContract.issue(1000, receiptorAccount1); | |||
assetContract.transfer(receiptorAccount1, receiptorAccount2, 600); | |||
// assetContract. | |||
// -------------------------------------- | |||
// TX 准备就绪; | |||