@@ -1,10 +1,11 @@ | |||
package com.jd.blockchain.contract.engine; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface ContractCode { | |||
String getAddress(); | |||
Bytes getAddress(); | |||
long getVersion(); | |||
@@ -1,5 +1,7 @@ | |||
package com.jd.blockchain.contract.engine; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 合约引擎; | |||
* | |||
@@ -16,7 +18,7 @@ public interface ContractEngine { | |||
* @param address | |||
* @return | |||
*/ | |||
ContractCode getContract(String address, long version); | |||
ContractCode getContract(Bytes address, long version); | |||
/** | |||
* 装入合约代码;<br> | |||
@@ -27,6 +29,6 @@ public interface ContractEngine { | |||
* @param code | |||
* @return | |||
*/ | |||
ContractCode setupContract(String address, long version, byte[] code); | |||
ContractCode setupContract(Bytes address, long version, byte[] code); | |||
} |
@@ -4,18 +4,18 @@ import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.contract.engine.ContractEngine; | |||
import com.jd.blockchain.runtime.Module; | |||
import com.jd.blockchain.runtime.RuntimeContext; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class JVMContractEngine implements ContractEngine { | |||
private RuntimeContext runtimeContext = RuntimeContext.get(); | |||
// private RuntimeContext runtimeContext = ModularRuntimeContext.setup(System.getProperty("user.dir")); | |||
private String getCodeName(String address, long version) { | |||
return address + "_" + version; | |||
private String getCodeName(Bytes address, long version) { | |||
return address.toBase58() + "_" + version; | |||
} | |||
@Override | |||
public ContractCode getContract(String address, long version) { | |||
public ContractCode getContract(Bytes address, long version) { | |||
String codeName = getCodeName(address, version); | |||
Module module = runtimeContext.getDynamicModule(codeName); | |||
if (module == null) { | |||
@@ -25,7 +25,7 @@ public class JVMContractEngine implements ContractEngine { | |||
} | |||
@Override | |||
public ContractCode setupContract(String address, long version, byte[] code) { | |||
public ContractCode setupContract(Bytes address, long version, byte[] code) { | |||
//is there the contractCode before setup? if yes ,then return; | |||
ContractCode contractCode = getContract(address,version); | |||
if(contractCode != null){ | |||
@@ -14,6 +14,7 @@ import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.runtime.Module; | |||
import com.jd.blockchain.utils.BaseConstant; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* contract code based jvm | |||
@@ -22,18 +23,18 @@ import com.jd.blockchain.utils.BaseConstant; | |||
public class JavaContractCode implements ContractCode { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); | |||
private Module codeModule; | |||
private String address; | |||
private Bytes address; | |||
private long version; | |||
private ContractEventContext contractEventContext; | |||
public JavaContractCode(String address, long version, Module codeModule) { | |||
public JavaContractCode(Bytes address, long version, Module codeModule) { | |||
this.address = address; | |||
this.version = version; | |||
this.codeModule = codeModule; | |||
} | |||
@Override | |||
public String getAddress() { | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@@ -8,11 +8,8 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
public class ContractAccount implements AccountHeader { | |||
// private static final String CONTRACT_INFO_PREFIX = "INFO" + | |||
// LedgerConsts.KEY_SEPERATOR; | |||
private static final Bytes CONTRACT_INFO_PREFIX = Bytes.fromString("INFO" + LedgerConsts.KEY_SEPERATOR); | |||
// private static final String CHAIN_CODE_KEY = "CHAIN-CODE"; | |||
private static final Bytes CHAIN_CODE_KEY = Bytes.fromString("CHAIN-CODE"); | |||
private BaseAccount accBase; | |||
@@ -74,7 +71,6 @@ public class ContractAccount implements AccountHeader { | |||
private Bytes encodePropertyKey(Bytes key) { | |||
return CONTRACT_INFO_PREFIX.concat(key); | |||
// return key.concatTo(CONTRACT_INFO_PREFIX); | |||
} | |||
} |
@@ -1,49 +1,72 @@ | |||
package com.jd.blockchain.ledger.core.impl.handles; | |||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | |||
import org.springframework.stereotype.Service; | |||
import com.jd.blockchain.contract.LocalContractEventContext; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.contract.engine.ContractEngine; | |||
import com.jd.blockchain.contract.engine.ContractServiceProviders; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.core.*; | |||
import com.jd.blockchain.ledger.core.ContractAccount; | |||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.LedgerException; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.impl.LedgerQueryService; | |||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | |||
import org.springframework.stereotype.Service; | |||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | |||
@Service | |||
public class ContractEventSendOperationHandle implements OperationHandle { | |||
private static final ContractEngine JVM_ENGINE; | |||
static { | |||
JVM_ENGINE = ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine(); | |||
} | |||
@Override | |||
public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | |||
LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | |||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | |||
// 先从账本校验合约的有效性; | |||
// 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; | |||
if (!previousBlockDataset.getContractAccountSet().contains(contractOP.getContractAddress())) { | |||
throw new LedgerException( | |||
String.format("Target contract of ContractEvent was not registered! --[ContractAddress=%s]", | |||
contractOP.getContractAddress())); | |||
ContractAccountSet contractSet = previousBlockDataset.getContractAccountSet(); | |||
if (!contractSet.contains(contractOP.getContractAddress())) { | |||
throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", | |||
contractOP.getContractAddress())); | |||
} | |||
//创建合约的账本上下文实例; | |||
LedgerQueryService queryService = new LedgerQueryService(ledgerService) ; | |||
// 创建合约的账本上下文实例; | |||
LedgerQueryService queryService = new LedgerQueryService(ledgerService); | |||
ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext); | |||
// TODO:从合约引擎加载合约,执行合约代码; | |||
ContractAccount contract = previousBlockDataset.getContractAccountSet() | |||
.getContract(contractOP.getContractAddress()); | |||
try { | |||
// 在调用方法前,需要加载上下文信息; | |||
LocalContractEventContext localContractEventContext = new LocalContractEventContext( | |||
requestContext.getRequest().getTransactionContent().getLedgerHash(),contract.getChainCode(), contractOP.getEvent()); | |||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()). | |||
setLedgerContext(ledgerContext); | |||
ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine().setupContract( | |||
contract.getAddress().toBase58(),contract.getChaincodeVersion(),contract.getChainCode()). | |||
processEvent(localContractEventContext); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
// 先检查合约引擎是否已经加载合约;如果未加载,再从账本中读取合约代码并装载到引擎中执行; | |||
ContractAccount contract = contractSet.getContract(contractOP.getContractAddress()); | |||
if (contract == null) { | |||
throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", | |||
contractOP.getContractAddress())); | |||
} | |||
// 创建合约上下文; | |||
LocalContractEventContext localContractEventContext = new LocalContractEventContext( | |||
requestContext.getRequest().getTransactionContent().getLedgerHash(), contractOP.getEvent()); | |||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) | |||
.setLedgerContext(ledgerContext); | |||
ContractCode contractCode = JVM_ENGINE.getContract(contract.getAddress(), contract.getChaincodeVersion()); | |||
if (contractCode == null) { | |||
// 装载合约; | |||
contractCode = JVM_ENGINE.setupContract(contract.getAddress(), contract.getChaincodeVersion(), | |||
contract.getChainCode()); | |||
} | |||
// 处理合约事件; | |||
contractCode.processEvent(localContractEventContext); | |||
} | |||
@Override | |||
@@ -1,11 +1,10 @@ | |||
package com.jd.blockchain.contract; | |||
import java.util.Set; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.io.ByteArray; | |||
import java.util.Set; | |||
/** | |||
* @Author zhaogw | |||
@@ -21,10 +20,10 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable | |||
private Set<BlockchainIdentity> contractOwners; | |||
private LedgerContext ledgerContext; | |||
public LocalContractEventContext(HashDigest ledgeHash, byte[] chainCode, String event){ | |||
public LocalContractEventContext(HashDigest ledgeHash, String event){ | |||
this.ledgeHash = ledgeHash; | |||
this.event = event; | |||
this.chainCode = chainCode; | |||
// this.chainCode = chainCode; | |||
} | |||
@Override | |||
@@ -92,14 +91,14 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable | |||
return this; | |||
} | |||
public byte[] getChainCode() { | |||
return chainCode; | |||
} | |||
public LocalContractEventContext setChainCode(byte[] chainCode) { | |||
this.chainCode = chainCode; | |||
return this; | |||
} | |||
// public byte[] getChainCode() { | |||
// return chainCode; | |||
// } | |||
// | |||
// public LocalContractEventContext setChainCode(byte[] chainCode) { | |||
// this.chainCode = chainCode; | |||
// return this; | |||
// } | |||
public LocalContractEventContext setArgs(byte[] args) { | |||
this.args = args; | |||
@@ -8,6 +8,12 @@ import com.jd.blockchain.utils.io.BytesSerializable; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.utils.io.RuntimeIOException; | |||
/** | |||
* Bytes 被设计为不可变对象; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class Bytes implements BytesSerializable { | |||
public static final Bytes EMPTY = new Bytes(BytesUtils.EMPTY_BYTES); | |||
@@ -38,7 +44,7 @@ public class Bytes implements BytesSerializable { | |||
} | |||
public Bytes() { | |||
prefix=null; | |||
prefix = null; | |||
data = null; | |||
hashCode = hashCode(1); | |||
} | |||
@@ -47,7 +53,7 @@ public class Bytes implements BytesSerializable { | |||
if (data == null) { | |||
throw new IllegalArgumentException("data is null!"); | |||
} | |||
this.prefix=null; | |||
this.prefix = null; | |||
this.data = data; | |||
hashCode = hashCode(1); | |||
} | |||
@@ -56,30 +62,30 @@ public class Bytes implements BytesSerializable { | |||
if (data == null) { | |||
throw new IllegalArgumentException("data is null!"); | |||
} | |||
this.prefix=prefix; | |||
this.prefix = prefix; | |||
this.data = data; | |||
// setPrefix(prefix); | |||
// setPrefix(prefix); | |||
hashCode = hashCode(1); | |||
} | |||
public Bytes(Bytes prefix, Bytes data) { | |||
// setData(data.toBytes()); | |||
// setPrefix(prefix); | |||
// setData(data.toBytes()); | |||
// setPrefix(prefix); | |||
if (data == null) { | |||
throw new IllegalArgumentException("data is null!"); | |||
} | |||
this.prefix=prefix; | |||
this.prefix = prefix; | |||
this.data = data.toBytes(); | |||
hashCode = hashCode(1); | |||
} | |||
// private void setData(byte[] data) { | |||
// if (data == null) { | |||
// throw new IllegalArgumentException("data is null!"); | |||
// } | |||
// this.data = data; | |||
// } | |||
// private void setData(byte[] data) { | |||
// if (data == null) { | |||
// throw new IllegalArgumentException("data is null!"); | |||
// } | |||
// this.data = data; | |||
// } | |||
/** | |||
* 返回当前的字节数组(不包含前缀对象); | |||
@@ -98,16 +104,16 @@ public class Bytes implements BytesSerializable { | |||
return new Bytes(Base58Utils.decode(str)); | |||
} | |||
// /** | |||
// * 连接指定的前缀后面;此操作并不会更改“prefix”参数; | |||
// * | |||
// * @param prefix | |||
// * @return | |||
// */ | |||
// private Bytes setPrefix(Bytes prefix) { | |||
// this.prefix = prefix; | |||
// return this; | |||
// } | |||
// /** | |||
// * 连接指定的前缀后面;此操作并不会更改“prefix”参数; | |||
// * | |||
// * @param prefix | |||
// * @return | |||
// */ | |||
// private Bytes setPrefix(Bytes prefix) { | |||
// this.prefix = prefix; | |||
// return this; | |||
// } | |||
public Bytes concat(Bytes key) { | |||
return new Bytes(this, key); | |||