@@ -1,10 +1,11 @@ | |||||
package com.jd.blockchain.contract.engine; | package com.jd.blockchain.contract.engine; | ||||
import com.jd.blockchain.contract.ContractEventContext; | import com.jd.blockchain.contract.ContractEventContext; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
public interface ContractCode { | public interface ContractCode { | ||||
String getAddress(); | |||||
Bytes getAddress(); | |||||
long getVersion(); | long getVersion(); | ||||
@@ -1,5 +1,7 @@ | |||||
package com.jd.blockchain.contract.engine; | package com.jd.blockchain.contract.engine; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
/** | /** | ||||
* 合约引擎; | * 合约引擎; | ||||
* | * | ||||
@@ -16,7 +18,7 @@ public interface ContractEngine { | |||||
* @param address | * @param address | ||||
* @return | * @return | ||||
*/ | */ | ||||
ContractCode getContract(String address, long version); | |||||
ContractCode getContract(Bytes address, long version); | |||||
/** | /** | ||||
* 装入合约代码;<br> | * 装入合约代码;<br> | ||||
@@ -27,6 +29,6 @@ public interface ContractEngine { | |||||
* @param code | * @param code | ||||
* @return | * @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.contract.engine.ContractEngine; | ||||
import com.jd.blockchain.runtime.Module; | import com.jd.blockchain.runtime.Module; | ||||
import com.jd.blockchain.runtime.RuntimeContext; | import com.jd.blockchain.runtime.RuntimeContext; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
public class JVMContractEngine implements ContractEngine { | public class JVMContractEngine implements ContractEngine { | ||||
private RuntimeContext runtimeContext = RuntimeContext.get(); | 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 | @Override | ||||
public ContractCode getContract(String address, long version) { | |||||
public ContractCode getContract(Bytes address, long version) { | |||||
String codeName = getCodeName(address, version); | String codeName = getCodeName(address, version); | ||||
Module module = runtimeContext.getDynamicModule(codeName); | Module module = runtimeContext.getDynamicModule(codeName); | ||||
if (module == null) { | if (module == null) { | ||||
@@ -25,7 +25,7 @@ public class JVMContractEngine implements ContractEngine { | |||||
} | } | ||||
@Override | @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; | //is there the contractCode before setup? if yes ,then return; | ||||
ContractCode contractCode = getContract(address,version); | ContractCode contractCode = getContract(address,version); | ||||
if(contractCode != null){ | if(contractCode != null){ | ||||
@@ -14,6 +14,7 @@ import com.jd.blockchain.contract.ContractEventContext; | |||||
import com.jd.blockchain.contract.engine.ContractCode; | import com.jd.blockchain.contract.engine.ContractCode; | ||||
import com.jd.blockchain.runtime.Module; | import com.jd.blockchain.runtime.Module; | ||||
import com.jd.blockchain.utils.BaseConstant; | import com.jd.blockchain.utils.BaseConstant; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
/** | /** | ||||
* contract code based jvm | * contract code based jvm | ||||
@@ -22,18 +23,18 @@ import com.jd.blockchain.utils.BaseConstant; | |||||
public class JavaContractCode implements ContractCode { | public class JavaContractCode implements ContractCode { | ||||
private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); | private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); | ||||
private Module codeModule; | private Module codeModule; | ||||
private String address; | |||||
private Bytes address; | |||||
private long version; | private long version; | ||||
private ContractEventContext contractEventContext; | private ContractEventContext contractEventContext; | ||||
public JavaContractCode(String address, long version, Module codeModule) { | |||||
public JavaContractCode(Bytes address, long version, Module codeModule) { | |||||
this.address = address; | this.address = address; | ||||
this.version = version; | this.version = version; | ||||
this.codeModule = codeModule; | this.codeModule = codeModule; | ||||
} | } | ||||
@Override | @Override | ||||
public String getAddress() { | |||||
public Bytes getAddress() { | |||||
return address; | return address; | ||||
} | } | ||||
@@ -8,11 +8,8 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||||
public class ContractAccount implements AccountHeader { | 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 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 static final Bytes CHAIN_CODE_KEY = Bytes.fromString("CHAIN-CODE"); | ||||
private BaseAccount accBase; | private BaseAccount accBase; | ||||
@@ -74,7 +71,6 @@ public class ContractAccount implements AccountHeader { | |||||
private Bytes encodePropertyKey(Bytes key) { | private Bytes encodePropertyKey(Bytes key) { | ||||
return CONTRACT_INFO_PREFIX.concat(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; | 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.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.contract.engine.ContractServiceProviders; | ||||
import com.jd.blockchain.ledger.ContractEventSendOperation; | import com.jd.blockchain.ledger.ContractEventSendOperation; | ||||
import com.jd.blockchain.ledger.Operation; | 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.LedgerQueryService; | ||||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | ||||
import org.springframework.stereotype.Service; | |||||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | |||||
@Service | @Service | ||||
public class ContractEventSendOperationHandle implements OperationHandle { | public class ContractEventSendOperationHandle implements OperationHandle { | ||||
private static final ContractEngine JVM_ENGINE; | |||||
static { | |||||
JVM_ENGINE = ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine(); | |||||
} | |||||
@Override | @Override | ||||
public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | ||||
LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | ||||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | 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); | 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 | @Override | ||||
@@ -1,11 +1,10 @@ | |||||
package com.jd.blockchain.contract; | package com.jd.blockchain.contract; | ||||
import java.util.Set; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.TransactionRequest; | import com.jd.blockchain.ledger.TransactionRequest; | ||||
import com.jd.blockchain.utils.io.ByteArray; | |||||
import java.util.Set; | |||||
/** | /** | ||||
* @Author zhaogw | * @Author zhaogw | ||||
@@ -21,10 +20,10 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable | |||||
private Set<BlockchainIdentity> contractOwners; | private Set<BlockchainIdentity> contractOwners; | ||||
private LedgerContext ledgerContext; | private LedgerContext ledgerContext; | ||||
public LocalContractEventContext(HashDigest ledgeHash, byte[] chainCode, String event){ | |||||
public LocalContractEventContext(HashDigest ledgeHash, String event){ | |||||
this.ledgeHash = ledgeHash; | this.ledgeHash = ledgeHash; | ||||
this.event = event; | this.event = event; | ||||
this.chainCode = chainCode; | |||||
// this.chainCode = chainCode; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -92,14 +91,14 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable | |||||
return this; | 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) { | public LocalContractEventContext setArgs(byte[] args) { | ||||
this.args = 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.BytesUtils; | ||||
import com.jd.blockchain.utils.io.RuntimeIOException; | import com.jd.blockchain.utils.io.RuntimeIOException; | ||||
/** | |||||
* Bytes 被设计为不可变对象; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public class Bytes implements BytesSerializable { | public class Bytes implements BytesSerializable { | ||||
public static final Bytes EMPTY = new Bytes(BytesUtils.EMPTY_BYTES); | public static final Bytes EMPTY = new Bytes(BytesUtils.EMPTY_BYTES); | ||||
@@ -38,7 +44,7 @@ public class Bytes implements BytesSerializable { | |||||
} | } | ||||
public Bytes() { | public Bytes() { | ||||
prefix=null; | |||||
prefix = null; | |||||
data = null; | data = null; | ||||
hashCode = hashCode(1); | hashCode = hashCode(1); | ||||
} | } | ||||
@@ -47,7 +53,7 @@ public class Bytes implements BytesSerializable { | |||||
if (data == null) { | if (data == null) { | ||||
throw new IllegalArgumentException("data is null!"); | throw new IllegalArgumentException("data is null!"); | ||||
} | } | ||||
this.prefix=null; | |||||
this.prefix = null; | |||||
this.data = data; | this.data = data; | ||||
hashCode = hashCode(1); | hashCode = hashCode(1); | ||||
} | } | ||||
@@ -56,30 +62,30 @@ public class Bytes implements BytesSerializable { | |||||
if (data == null) { | if (data == null) { | ||||
throw new IllegalArgumentException("data is null!"); | throw new IllegalArgumentException("data is null!"); | ||||
} | } | ||||
this.prefix=prefix; | |||||
this.prefix = prefix; | |||||
this.data = data; | this.data = data; | ||||
// setPrefix(prefix); | |||||
// setPrefix(prefix); | |||||
hashCode = hashCode(1); | hashCode = hashCode(1); | ||||
} | } | ||||
public Bytes(Bytes prefix, Bytes data) { | public Bytes(Bytes prefix, Bytes data) { | ||||
// setData(data.toBytes()); | |||||
// setPrefix(prefix); | |||||
// setData(data.toBytes()); | |||||
// setPrefix(prefix); | |||||
if (data == null) { | if (data == null) { | ||||
throw new IllegalArgumentException("data is null!"); | throw new IllegalArgumentException("data is null!"); | ||||
} | } | ||||
this.prefix=prefix; | |||||
this.prefix = prefix; | |||||
this.data = data.toBytes(); | this.data = data.toBytes(); | ||||
hashCode = hashCode(1); | 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)); | 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) { | public Bytes concat(Bytes key) { | ||||
return new Bytes(this, key); | return new Bytes(this, key); | ||||