# Conflicts: # source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java # source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployExeUtil.java # source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java # source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java # source/gateway/src/main/java/com/jd/blockchain/gateway/web/TxProcessingController.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbstractContractEventHandle.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbtractContractEventSendOperationHandle.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/JVMContractEventSendOperationHandle.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java # source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingHandle.java # source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.javatags/1.1.0
@@ -5,15 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>jdchain-root</artifactId> | <artifactId>jdchain-root</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>base</artifactId> | <artifactId>base</artifactId> | ||||
<dependencies> | |||||
<dependency> | |||||
<groupId>org.slf4j</groupId> | |||||
<artifactId>slf4j-api</artifactId> | |||||
</dependency> | |||||
</dependencies> | |||||
</project> | </project> |
@@ -8,11 +8,11 @@ package com.jd.blockchain.consts; | |||||
*/ | */ | ||||
public interface DataCodes { | public interface DataCodes { | ||||
public static final int BYTES_VALUE = 0x80; | |||||
public static final int BYTES_VALUE_LIST = 0x81; | |||||
public static final int BYTES_VALUE = 0x080; | |||||
public static final int BYTES_VALUE_LIST = 0x081; | |||||
public static final int BLOCK_CHAIN_IDENTITY = 0x90; | |||||
public static final int BLOCK_CHAIN_IDENTITY = 0x090; | |||||
public static final int BLOCK = 0x100; | public static final int BLOCK = 0x100; | ||||
@@ -22,6 +22,8 @@ public interface DataCodes { | |||||
public static final int DATA_SNAPSHOT = 0x130; | public static final int DATA_SNAPSHOT = 0x130; | ||||
// public static final int LEDGER_ADMIN_DATA = 0x131; | |||||
public static final int TX = 0x200; | public static final int TX = 0x200; | ||||
public static final int TX_LEDGER = 0x201; | public static final int TX_LEDGER = 0x201; | ||||
@@ -52,12 +54,37 @@ public interface DataCodes { | |||||
public static final int TX_RESPONSE = 0x350; | public static final int TX_RESPONSE = 0x350; | ||||
public static final int TX_OP_RESULT = 0x360; | public static final int TX_OP_RESULT = 0x360; | ||||
public static final int TX_OP_ROLE_CONFIGURE = 0x370; | |||||
public static final int TX_OP_ROLE_CONFIGURE_ENTRY = 0x371; | |||||
public static final int TX_OP_USER_ROLES_AUTHORIZE = 0x372; | |||||
public static final int TX_OP_USER_ROLE_AUTHORIZE_ENTRY = 0x373; | |||||
// enum types of permissions; | |||||
public static final int ENUM_TX_PERMISSION = 0x401; | |||||
public static final int ENUM_LEDGER_PERMISSION = 0x402; | |||||
public static final int ENUM_MULTI_ROLES_POLICY = 0x403; | |||||
public static final int PRIVILEGE_SET = 0x410; | |||||
public static final int ROLE_SET = 0x411; | |||||
public static final int SECURITY_INIT_SETTING = 0x420; | |||||
public static final int SECURITY_ROLE_INIT_SETTING = 0x421; | |||||
public static final int SECURITY_USER_AUTH_INIT_SETTING = 0x422; | |||||
// contract types of metadata; | |||||
public static final int METADATA = 0x600; | public static final int METADATA = 0x600; | ||||
public static final int METADATA_V2 = 0x601; | |||||
public static final int METADATA_INIT_SETTING = 0x610; | public static final int METADATA_INIT_SETTING = 0x610; | ||||
public static final int METADATA_INIT_PERMISSION = 0x611; | |||||
public static final int METADATA_INIT_PROPOSAL = 0x611; | |||||
public static final int METADATA_INIT_DECISION = 0x612; | public static final int METADATA_INIT_DECISION = 0x612; | ||||
@@ -65,14 +92,14 @@ public interface DataCodes { | |||||
public static final int METADATA_CONSENSUS_PARTICIPANT = 0x621; | public static final int METADATA_CONSENSUS_PARTICIPANT = 0x621; | ||||
// public static final int METADATA_CONSENSUS_NODE = 0x630; | |||||
public static final int METADATA_CONSENSUS_SETTING = 0x631; | |||||
// public static final int METADATA_PARTICIPANT_INFO = 0x640; | |||||
// public static final int METADATA_CONSENSUS_NODE = 0x630; | |||||
// | |||||
// public static final int METADATA_CONSENSUS_SETTING = 0x631; | |||||
// | |||||
// public static final int METADATA_PARTICIPANT_INFO = 0x640; | |||||
public static final int METADATA_CRYPTO_SETTING = 0x642; | public static final int METADATA_CRYPTO_SETTING = 0x642; | ||||
public static final int METADATA_CRYPTO_SETTING_PROVIDER = 0x643; | public static final int METADATA_CRYPTO_SETTING_PROVIDER = 0x643; | ||||
// public static final int ACCOUNT = 0x700; | // public static final int ACCOUNT = 0x700; | ||||
@@ -83,11 +110,10 @@ public interface DataCodes { | |||||
public static final int DATA = 0x900; | public static final int DATA = 0x900; | ||||
//contract related; | |||||
// contract related; | |||||
public static final int CONTRACT = 0xA00; | public static final int CONTRACT = 0xA00; | ||||
//...0xA19 | |||||
// ...0xA19 | |||||
public static final int HASH = 0xB00; | public static final int HASH = 0xB00; | ||||
public static final int HASH_OBJECT = 0xB10; | public static final int HASH_OBJECT = 0xB10; | ||||
@@ -152,4 +178,5 @@ public interface DataCodes { | |||||
public static final int CONSENSUS_MSGQUEUE_BLOCK_SETTINGS = CONSENSUS_MSGQUEUE | 0x05; | public static final int CONSENSUS_MSGQUEUE_BLOCK_SETTINGS = CONSENSUS_MSGQUEUE | 0x05; | ||||
} | } |
@@ -0,0 +1,19 @@ | |||||
package com.jd.blockchain.consts; | |||||
import java.util.TimeZone; | |||||
public class Global { | |||||
public static final String DEFAULT_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSZ"; | |||||
public static final String DEFAULT_TIME_ZONE = "GMT+08:00"; | |||||
static { | |||||
initialize(); | |||||
} | |||||
public static void initialize() { | |||||
TimeZone.setDefault(TimeZone.getTimeZone(DEFAULT_TIME_ZONE)); | |||||
} | |||||
} |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>jdchain-root</artifactId> | <artifactId>jdchain-root</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>binary-proto</artifactId> | <artifactId>binary-proto</artifactId> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>consensus</artifactId> | <artifactId>consensus</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>consensus-bftsmart</artifactId> | <artifactId>consensus-bftsmart</artifactId> | ||||
@@ -6,6 +6,7 @@ import java.util.concurrent.CopyOnWriteArrayList; | |||||
import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||
import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||
import bftsmart.tom.*; | import bftsmart.tom.*; | ||||
import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import com.jd.blockchain.consensus.ConsensusManageService; | import com.jd.blockchain.consensus.ConsensusManageService; | ||||
@@ -32,6 +33,8 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
private static Logger LOGGER = LoggerFactory.getLogger(BftsmartNodeServer.class); | private static Logger LOGGER = LoggerFactory.getLogger(BftsmartNodeServer.class); | ||||
private static final String DEFAULT_BINDING_HOST = "0.0.0.0"; | |||||
private List<StateHandle> stateHandles = new CopyOnWriteArrayList<>(); | private List<StateHandle> stateHandles = new CopyOnWriteArrayList<>(); | ||||
// TODO 暂不处理队列溢出问题 | // TODO 暂不处理队列溢出问题 | ||||
@@ -56,6 +59,8 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
private TOMConfiguration tomConfig; | private TOMConfiguration tomConfig; | ||||
private TOMConfiguration outerTomConfig; | |||||
private HostsConfig hostsConfig; | private HostsConfig hostsConfig; | ||||
private Properties systemConfig; | private Properties systemConfig; | ||||
@@ -123,14 +128,13 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
return; | return; | ||||
} | } | ||||
// protected void initConfig(int id, String systemConfig, String hostsConfig) { | |||||
// | |||||
// this.tomConfig = new TOMConfiguration(id, systemConfig, hostsConfig); | |||||
// | |||||
// } | |||||
protected void initConfig(int id, Properties systemsConfig, HostsConfig hostConfig) { | protected void initConfig(int id, Properties systemsConfig, HostsConfig hostConfig) { | ||||
byte[] serialHostConf = BinarySerializeUtils.serialize(hostConfig); | |||||
Properties sysConfClone = (Properties)systemsConfig.clone(); | |||||
int port = hostConfig.getPort(id); | |||||
hostConfig.add(id, DEFAULT_BINDING_HOST, port); | |||||
this.tomConfig = new TOMConfiguration(id, systemsConfig, hostConfig); | this.tomConfig = new TOMConfiguration(id, systemsConfig, hostConfig); | ||||
this.outerTomConfig = new TOMConfiguration(id, sysConfClone, BinarySerializeUtils.deserialize(serialHostConf)); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -149,7 +153,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
} | } | ||||
public TOMConfiguration getTomConfig() { | public TOMConfiguration getTomConfig() { | ||||
return tomConfig; | |||||
return outerTomConfig; | |||||
} | } | ||||
public int getId() { | public int getId() { | ||||
@@ -161,7 +165,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
throw new IllegalArgumentException("ReplicaID is negative!"); | throw new IllegalArgumentException("ReplicaID is negative!"); | ||||
} | } | ||||
this.tomConfig.setProcessId(id); | this.tomConfig.setProcessId(id); | ||||
this.outerTomConfig.setProcessId(id); | |||||
} | } | ||||
public BftsmartConsensusSettings getConsensusSetting() { | public BftsmartConsensusSettings getConsensusSetting() { | ||||
@@ -243,6 +247,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
messageHandle.commitBatch(realmName, batchId); | messageHandle.commitBatch(realmName, batchId); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
// todo 需要处理应答码 404 | // todo 需要处理应答码 404 | ||||
LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); | |||||
messageHandle.rollbackBatch(realmName, batchId, TransactionState.CONSENSUS_ERROR.CODE); | messageHandle.rollbackBatch(realmName, batchId, TransactionState.CONSENSUS_ERROR.CODE); | ||||
} | } | ||||
@@ -309,7 +314,6 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
try { | try { | ||||
LOGGER.debug("Start replica...[ID=" + getId() + "]"); | LOGGER.debug("Start replica...[ID=" + getId() + "]"); | ||||
// 调整绑定Host | |||||
this.replica = new ServiceReplica(tomConfig, this, this); | this.replica = new ServiceReplica(tomConfig, this, this); | ||||
this.topology = new BftsmartTopology(replica.getReplicaContext().getCurrentView()); | this.topology = new BftsmartTopology(replica.getReplicaContext().getCurrentView()); | ||||
status = Status.RUNNING; | status = Status.RUNNING; | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>consensus</artifactId> | <artifactId>consensus</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>consensus-framework</artifactId> | <artifactId>consensus-framework</artifactId> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>consensus</artifactId> | <artifactId>consensus</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>consensus-mq</artifactId> | <artifactId>consensus-mq</artifactId> | ||||
@@ -20,9 +20,9 @@ import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||||
import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | ||||
import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | ||||
import com.jd.blockchain.crypto.AddressEncoding; | import com.jd.blockchain.crypto.AddressEncoding; | ||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.PropertiesUtils; | import com.jd.blockchain.utils.PropertiesUtils; | ||||
import com.jd.blockchain.utils.codec.Base58Utils; | import com.jd.blockchain.utils.codec.Base58Utils; | ||||
@@ -129,7 +129,7 @@ public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilde | |||||
String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | ||||
String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey); | String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey); | ||||
PubKey pubKey = KeyGenCommand.decodePubKey(base58PubKey); | |||||
PubKey pubKey = KeyGenUtils.decodePubKey(base58PubKey); | |||||
// PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey)); | // PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey)); | ||||
resolvingProps.remove(keyOfPubkey); | resolvingProps.remove(keyOfPubkey); | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>jdchain-root</artifactId> | <artifactId>jdchain-root</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>consensus</artifactId> | <artifactId>consensus</artifactId> | ||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>contract</artifactId> | <artifactId>contract</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>contract-framework</artifactId> | <artifactId>contract-framework</artifactId> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>contract</artifactId> | <artifactId>contract</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>contract-jvm</artifactId> | <artifactId>contract-jvm</artifactId> | ||||
@@ -0,0 +1,25 @@ | |||||
package com.jd.blockchain.contract.jvm; | |||||
import com.jd.blockchain.contract.ContractType; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public class InstantiatedContractCode<T> extends AbstractContractCode { | |||||
private T instance; | |||||
public InstantiatedContractCode(Bytes address, long version, Class<T> delaredInterface, T instance) { | |||||
super(address, version, resolveContractDefinition(delaredInterface, instance.getClass())); | |||||
this.instance = instance; | |||||
} | |||||
private static ContractDefinition resolveContractDefinition(Class<?> declaredIntf, Class<?> implementedClass) { | |||||
ContractType contractType = ContractType.resolve(declaredIntf); | |||||
return new ContractDefinition(contractType, implementedClass); | |||||
} | |||||
@Override | |||||
protected T getContractInstance() { | |||||
return instance; | |||||
} | |||||
} |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>contract</artifactId> | <artifactId>contract</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>contract-maven-plugin</artifactId> | <artifactId>contract-maven-plugin</artifactId> | ||||
<packaging>maven-plugin</packaging> | <packaging>maven-plugin</packaging> | ||||
@@ -0,0 +1,193 @@ | |||||
package com.jd.blockchain; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||||
import com.jd.blockchain.ledger.EndpointRequest; | |||||
import com.jd.blockchain.ledger.NodeRequest; | |||||
import com.jd.blockchain.ledger.Operation; | |||||
import com.jd.blockchain.ledger.PreparedTransaction; | |||||
import com.jd.blockchain.ledger.TransactionContent; | |||||
import com.jd.blockchain.ledger.TransactionContentBody; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
import com.jd.blockchain.ledger.TransactionResponse; | |||||
import com.jd.blockchain.ledger.TransactionTemplate; | |||||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||||
import com.jd.blockchain.sdk.BlockchainService; | |||||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.net.NetworkAddress; | |||||
/** | |||||
* @Author zhaogw | |||||
* @Date 2018/11/2 10:18 | |||||
*/ | |||||
public enum ContractDeployExeUtil { | |||||
instance; | |||||
private BlockchainService bcsrv; | |||||
private Bytes contractAddress; | |||||
public BlockchainKeypair getKeyPair(String pubPath, String prvPath, String rawPassword){ | |||||
PubKey pub = null; | |||||
PrivKey prv = null; | |||||
try { | |||||
prv = KeyGenUtils.readPrivKey(prvPath, KeyGenUtils.encodePassword(rawPassword)); | |||||
pub = KeyGenUtils.readPubKey(pubPath); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return new BlockchainKeypair(pub, prv); | |||||
} | |||||
public PubKey getPubKey(String pubPath){ | |||||
PubKey pub = null; | |||||
try { | |||||
if(pubPath == null){ | |||||
BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate(); | |||||
pub = contractKeyPair.getPubKey(); | |||||
}else { | |||||
pub = KeyGenUtils.readPubKey(pubPath); | |||||
} | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return pub; | |||||
} | |||||
public byte[] getChainCode(String path){ | |||||
byte[] chainCode = null; | |||||
File file = null; | |||||
InputStream input = null; | |||||
try { | |||||
file = new File(path); | |||||
input = new FileInputStream(file); | |||||
chainCode = new byte[input.available()]; | |||||
input.read(chainCode); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} finally { | |||||
try { | |||||
if(input!=null){ | |||||
input.close(); | |||||
} | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
return chainCode; | |||||
} | |||||
private void register(){ | |||||
DataContractRegistry.register(TransactionContent.class); | |||||
DataContractRegistry.register(TransactionContentBody.class); | |||||
DataContractRegistry.register(TransactionRequest.class); | |||||
DataContractRegistry.register(NodeRequest.class); | |||||
DataContractRegistry.register(EndpointRequest.class); | |||||
DataContractRegistry.register(TransactionResponse.class); | |||||
DataContractRegistry.register(DataAccountKVSetOperation.class); | |||||
DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class); | |||||
DataContractRegistry.register(Operation.class); | |||||
DataContractRegistry.register(ContractCodeDeployOperation.class); | |||||
DataContractRegistry.register(ContractEventSendOperation.class); | |||||
DataContractRegistry.register(DataAccountRegisterOperation.class); | |||||
DataContractRegistry.register(UserRegisterOperation.class); | |||||
} | |||||
public BlockchainService initBcsrv(String host, int port) { | |||||
if(bcsrv!=null){ | |||||
return bcsrv; | |||||
} | |||||
NetworkAddress addr = new NetworkAddress(host, port); | |||||
GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(addr); | |||||
bcsrv = gwsrvFact.getBlockchainService(); | |||||
return bcsrv; | |||||
} | |||||
public boolean deploy(HashDigest ledgerHash, BlockchainIdentity contractIdentity, BlockchainKeypair ownerKey, byte[] chainCode){ | |||||
register(); | |||||
TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||||
txTpl.contracts().deploy(contractIdentity, chainCode); | |||||
PreparedTransaction ptx = txTpl.prepare(); | |||||
ptx.sign(ownerKey); | |||||
// 提交并等待共识返回; | |||||
TransactionResponse txResp = ptx.commit(); | |||||
// 验证结果; | |||||
contractAddress = contractIdentity.getAddress(); | |||||
this.setContractAddress(contractAddress); | |||||
System.out.println("contract's address="+contractAddress); | |||||
return txResp.isSuccess(); | |||||
} | |||||
public boolean deploy(String host, int port, HashDigest ledgerHash, BlockchainKeypair ownerKey, byte[] chainCode){ | |||||
register(); | |||||
BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity(); | |||||
initBcsrv(host,port); | |||||
return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||||
} | |||||
// 根据用户指定的公钥生成合约地址 | |||||
public boolean deploy(String host, int port, String ledger,String ownerPubPath, String ownerPrvPath, | |||||
String ownerPassword, String chainCodePath,String pubPath){ | |||||
PubKey pubKey = getPubKey(pubPath); | |||||
BlockchainIdentity contractIdentity = new BlockchainIdentityData(pubKey); | |||||
byte[] chainCode = getChainCode(chainCodePath); | |||||
BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||||
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
initBcsrv(host,port); | |||||
return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||||
} | |||||
// 暂不支持从插件执行合约;此外,由于合约参数调用的格式发生变化,故此方法被废弃;by: huanghaiquan at 2019-04-30; | |||||
// public boolean exeContract(String ledger,String ownerPubPath, String ownerPrvPath, | |||||
// String ownerPassword,String event,String contractArgs){ | |||||
// BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||||
// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
// | |||||
// // 定义交易,传输最简单的数字、字符串、提取合约中的地址; | |||||
// TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||||
// txTpl.contractEvents().send(getContractAddress(),event,contractArgs.getBytes()); | |||||
// | |||||
// // 签名; | |||||
// PreparedTransaction ptx = txTpl.prepare(); | |||||
// ptx.sign(ownerKey); | |||||
// | |||||
// // 提交并等待共识返回; | |||||
// TransactionResponse txResp = ptx.commit(); | |||||
// | |||||
// // 验证结果; | |||||
// return txResp.isSuccess(); | |||||
// } | |||||
public Bytes getContractAddress() { | |||||
return contractAddress; | |||||
} | |||||
public void setContractAddress(Bytes contractAddress) { | |||||
this.contractAddress = contractAddress; | |||||
} | |||||
} |
@@ -0,0 +1,119 @@ | |||||
package com.jd.blockchain; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||||
import com.jd.blockchain.utils.StringUtils; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.io.FileUtils; | |||||
import org.apache.maven.plugin.AbstractMojo; | |||||
import org.apache.maven.plugin.MojoFailureException; | |||||
import org.apache.maven.plugins.annotations.Mojo; | |||||
import org.apache.maven.plugins.annotations.Parameter; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.util.Properties; | |||||
/** | |||||
* for contract remote deploy; | |||||
* @goal contractDeploy | |||||
* @phase process-sources | |||||
* @Author zhaogw | |||||
* @Date 2018/10/18 10:12 | |||||
*/ | |||||
@Mojo(name = "deploy") | |||||
public class ContractDeployMojo extends AbstractMojo { | |||||
Logger logger = LoggerFactory.getLogger(ContractDeployMojo.class); | |||||
@Parameter | |||||
private File config; | |||||
@Override | |||||
public void execute()throws MojoFailureException { | |||||
Properties prop = new Properties(); | |||||
InputStream input = null; | |||||
try { | |||||
input = new FileInputStream(config); | |||||
prop.load(input); | |||||
} catch (IOException ex) { | |||||
logger.error(ex.getMessage()); | |||||
throw new MojoFailureException("io error"); | |||||
} finally { | |||||
if (input != null) { | |||||
try { | |||||
input.close(); | |||||
} catch (IOException e) { | |||||
logger.error(e.getMessage()); | |||||
} | |||||
} | |||||
} | |||||
int port; | |||||
try { | |||||
port = Integer.parseInt(prop.getProperty("port")); | |||||
}catch (NumberFormatException e){ | |||||
logger.error(e.getMessage()); | |||||
throw new MojoFailureException("invalid port"); | |||||
} | |||||
String host = prop.getProperty("host"); | |||||
String ledger = prop.getProperty("ledger"); | |||||
String pubKey = prop.getProperty("pubKey"); | |||||
String prvKey = prop.getProperty("prvKey"); | |||||
String password = prop.getProperty("password"); | |||||
String contractPath = prop.getProperty("contractPath"); | |||||
if(StringUtils.isEmpty(host)){ | |||||
logger.info("host不能为空"); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(ledger)){ | |||||
logger.info("ledger不能为空."); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(pubKey)){ | |||||
logger.info("pubKey不能为空."); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(prvKey)){ | |||||
logger.info("prvKey不能为空."); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(contractPath)){ | |||||
logger.info("contractPath不能为空."); | |||||
return; | |||||
} | |||||
File contract = new File(contractPath); | |||||
if (!contract.isFile()){ | |||||
logger.info("文件"+contractPath+"不存在"); | |||||
return; | |||||
} | |||||
byte[] contractBytes = FileUtils.readBytes(contractPath); | |||||
PrivKey prv = KeyGenUtils.decodePrivKeyWithRawPassword(prvKey, password); | |||||
PubKey pub = KeyGenUtils.decodePubKey(pubKey); | |||||
BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(pub, prv); | |||||
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
StringBuffer sb = new StringBuffer(); | |||||
sb.append("host:"+ host).append(",port:"+port).append(",ledgerHash:"+ledgerHash.toBase58()). | |||||
append(",pubKey:"+pubKey).append(",prvKey:"+prv).append(",contractPath:"+contractPath); | |||||
logger.info(sb.toString()); | |||||
ContractDeployExeUtil.instance.deploy(host,port,ledgerHash, blockchainKeyPair, contractBytes); | |||||
} | |||||
} | |||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<artifactId>contract</artifactId> | <artifactId>contract</artifactId> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
@@ -4,7 +4,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>jdchain-root</artifactId> | <artifactId>jdchain-root</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>contract</artifactId> | <artifactId>contract</artifactId> | ||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>crypto</artifactId> | <artifactId>crypto</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>crypto-adv</artifactId> | <artifactId>crypto-adv</artifactId> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>crypto</artifactId> | <artifactId>crypto</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>crypto-classic</artifactId> | <artifactId>crypto-classic</artifactId> | ||||
@@ -7,6 +7,8 @@ import org.bouncycastle.crypto.CipherParameters; | |||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | ||||
import org.bouncycastle.crypto.params.*; | import org.bouncycastle.crypto.params.*; | ||||
import org.bouncycastle.crypto.signers.ECDSASigner; | import org.bouncycastle.crypto.signers.ECDSASigner; | ||||
import org.bouncycastle.jce.ECNamedCurveTable; | |||||
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; | |||||
import org.bouncycastle.math.ec.ECCurve; | import org.bouncycastle.math.ec.ECCurve; | ||||
import org.bouncycastle.math.ec.ECMultiplier; | import org.bouncycastle.math.ec.ECMultiplier; | ||||
import org.bouncycastle.math.ec.ECPoint; | import org.bouncycastle.math.ec.ECPoint; | ||||
@@ -28,12 +30,10 @@ public class ECDSAUtils { | |||||
// p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 | // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 | ||||
// the curve equation is y^2 = x^3 + 7. | // the curve equation is y^2 = x^3 + 7. | ||||
private static final X9ECParameters X9_PARAMS = SECNamedCurves.getByName("secp256k1"); | |||||
private static final ECCurve CURVE = X9_PARAMS.getCurve(); | |||||
private static final ECPoint ECDSA_G = X9_PARAMS.getG(); | |||||
private static final BigInteger ECDSA_H = X9_PARAMS.getH(); | |||||
private static final BigInteger ECDSA_N = X9_PARAMS.getN(); | |||||
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, ECDSA_G,ECDSA_N,ECDSA_H); | |||||
private static final ECNamedCurveParameterSpec PARAMS = ECNamedCurveTable.getParameterSpec("secp256k1"); | |||||
private static final ECCurve CURVE = PARAMS.getCurve(); | |||||
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters( | |||||
CURVE, PARAMS.getG(), PARAMS.getN(), PARAMS.getH()); | |||||
//-----------------Key Generation Algorithm----------------- | //-----------------Key Generation Algorithm----------------- | ||||
@@ -0,0 +1,20 @@ | |||||
package com.jd.blockchain; | |||||
import static org.junit.Assert.assertTrue; | |||||
import org.junit.Test; | |||||
/** | |||||
* Unit test for simple App. | |||||
*/ | |||||
public class AppTest | |||||
{ | |||||
/** | |||||
* Rigorous Test :-) | |||||
*/ | |||||
@Test | |||||
public void shouldAnswerWithTrue() | |||||
{ | |||||
assertTrue( true ); | |||||
} | |||||
} |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>crypto</artifactId> | <artifactId>crypto</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>crypto-framework</artifactId> | <artifactId>crypto-framework</artifactId> | ||||
@@ -0,0 +1,187 @@ | |||||
package com.jd.blockchain.crypto; | |||||
import java.util.Arrays; | |||||
import javax.crypto.SecretKey; | |||||
import com.jd.blockchain.utils.ConsoleUtils; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | |||||
import com.jd.blockchain.utils.io.FileUtils; | |||||
import com.jd.blockchain.utils.security.AESUtils; | |||||
import com.jd.blockchain.utils.security.DecryptionException; | |||||
import com.jd.blockchain.utils.security.ShaUtils; | |||||
public class KeyGenUtils { | |||||
private static final byte[] PUB_KEY_FILE_MAGICNUM = { (byte) 0xFF, 112, 117, 98 }; | |||||
private static final byte[] PRIV_KEY_FILE_MAGICNUM = { (byte) 0x00, 112, 114, 118 }; | |||||
/** | |||||
* 公钥编码输出为 Base58 字符; | |||||
* | |||||
* @param pubKey | |||||
* @return | |||||
*/ | |||||
public static String encodePubKey(PubKey pubKey) { | |||||
byte[] pubKeyBytes = BytesUtils.concat(PUB_KEY_FILE_MAGICNUM, pubKey.toBytes()); | |||||
String base58PubKey = Base58Utils.encode(pubKeyBytes); | |||||
return base58PubKey; | |||||
} | |||||
public static PubKey decodePubKey(String base58PubKey) { | |||||
byte[] keyBytes = Base58Utils.decode(base58PubKey); | |||||
return decodePubKey(keyBytes); | |||||
} | |||||
public static String encodePrivKey(PrivKey privKey, String base58Pwd) { | |||||
byte[] pwdBytes = Base58Utils.decode(base58Pwd); | |||||
return encodePrivKey(privKey, pwdBytes); | |||||
} | |||||
public static String encodePrivKey(PrivKey privKey, byte[] pwdBytes) { | |||||
byte[] encodedPrivKeyBytes = encryptPrivKey(privKey, pwdBytes); | |||||
String base58PrivKey = Base58Utils.encode(encodedPrivKeyBytes); | |||||
return base58PrivKey; | |||||
} | |||||
public static byte[] encryptPrivKey(PrivKey privKey, byte[] pwdBytes) { | |||||
SecretKey userKey = AESUtils.generateKey128(pwdBytes); | |||||
byte[] encryptedPrivKeyBytes = AESUtils.encrypt(privKey.toBytes(), userKey); | |||||
return BytesUtils.concat(PRIV_KEY_FILE_MAGICNUM, encryptedPrivKeyBytes); | |||||
} | |||||
/** | |||||
* @param encodedPubKeyBytes | |||||
* @return | |||||
*/ | |||||
private static PubKey decodePubKeyBytes(byte[] encodedPubKeyBytes) { | |||||
byte[] pubKeyBytes = Arrays.copyOfRange(encodedPubKeyBytes, PUB_KEY_FILE_MAGICNUM.length, | |||||
encodedPubKeyBytes.length); | |||||
return new PubKey(pubKeyBytes); | |||||
} | |||||
public static PrivKey decryptedPrivKeyBytes(byte[] encodedPrivKeyBytes, byte[] pwdBytes) { | |||||
// Read privKye; | |||||
SecretKey userKey = AESUtils.generateKey128(pwdBytes); | |||||
byte[] encryptedKeyBytes = Arrays.copyOfRange(encodedPrivKeyBytes, PRIV_KEY_FILE_MAGICNUM.length, | |||||
encodedPrivKeyBytes.length); | |||||
try { | |||||
byte[] plainKeyBytes = AESUtils.decrypt(encryptedKeyBytes, userKey); | |||||
return new PrivKey(plainKeyBytes); | |||||
} catch (DecryptionException e) { | |||||
throw new DecryptionException("Invalid password!", e); | |||||
} | |||||
} | |||||
public static PubKey readPubKey(String keyFile) { | |||||
String base58KeyString = FileUtils.readText(keyFile); | |||||
return decodePubKey(base58KeyString); | |||||
} | |||||
/** | |||||
* 解码公钥; | |||||
* | |||||
* @param encodedPubKeyBytes 从公钥; | |||||
* @return | |||||
*/ | |||||
public static PubKey decodePubKey(byte[] encodedPubKeyBytes) { | |||||
if (BytesUtils.startsWith(encodedPubKeyBytes, PUB_KEY_FILE_MAGICNUM)) { | |||||
// Read pubKey; | |||||
return decodePubKeyBytes(encodedPubKeyBytes); | |||||
} | |||||
throw new IllegalArgumentException("The specified bytes is not valid PubKey generated by the KeyGen tool!"); | |||||
} | |||||
/** | |||||
* 从控制台读取加密口令,以二进制数组形式返回原始口令的一次SHA256的结果; | |||||
* | |||||
* @return | |||||
*/ | |||||
public static byte[] readPassword() { | |||||
byte[] pwdBytes = ConsoleUtils.readPassword(); | |||||
return ShaUtils.hash_256(pwdBytes); | |||||
} | |||||
/** | |||||
* 对指定的原始密码进行编码生成用于加解密的密码; | |||||
* | |||||
* @param rawPassword | |||||
* @return | |||||
*/ | |||||
public static byte[] encodePassword(String rawPassword) { | |||||
byte[] pwdBytes = BytesUtils.toBytes(rawPassword, "UTF-8"); | |||||
return ShaUtils.hash_256(pwdBytes); | |||||
} | |||||
/** | |||||
* 对指定的原始密码进行编码生成用于加解密的密码; | |||||
* | |||||
* @param rawPassword | |||||
* @return | |||||
*/ | |||||
public static String encodePasswordAsBase58(String rawPassword) { | |||||
return Base58Utils.encode(encodePassword(rawPassword)); | |||||
} | |||||
/** | |||||
* 从控制台读取加密口令,以Base58字符串形式返回口令的一次SHA256的结果; | |||||
* | |||||
* @return | |||||
*/ | |||||
public static String readPasswordString() { | |||||
return Base58Utils.encode(readPassword()); | |||||
} | |||||
public static PrivKey readPrivKey(String keyFile, String base58Pwd) { | |||||
return readPrivKey(keyFile, Base58Utils.decode(base58Pwd)); | |||||
} | |||||
/** | |||||
* 从文件读取私钥; | |||||
* | |||||
* @param keyFile | |||||
* @param pwdBytes | |||||
* @return | |||||
*/ | |||||
public static PrivKey readPrivKey(String keyFile, byte[] pwdBytes) { | |||||
String base58KeyString = FileUtils.readText(keyFile); | |||||
byte[] keyBytes = Base58Utils.decode(base58KeyString); | |||||
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) { | |||||
throw new IllegalArgumentException("The specified file is not a private key file!"); | |||||
} | |||||
return decryptedPrivKeyBytes(keyBytes, pwdBytes); | |||||
} | |||||
public static PrivKey decodePrivKey(String base58Key, String base58Pwd) { | |||||
byte[] decryptedKey = Base58Utils.decode(base58Pwd); | |||||
return decodePrivKey(base58Key, decryptedKey); | |||||
} | |||||
public static PrivKey decodePrivKey(String base58Key, byte[] pwdBytes) { | |||||
byte[] keyBytes = Base58Utils.decode(base58Key); | |||||
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) { | |||||
throw new IllegalArgumentException("The specified file is not a private key file!"); | |||||
} | |||||
return decryptedPrivKeyBytes(keyBytes, pwdBytes); | |||||
} | |||||
public static PrivKey decodePrivKeyWithRawPassword(String base58Key, String rawPassword) { | |||||
byte[] pwdBytes = encodePassword(rawPassword); | |||||
byte[] keyBytes = Base58Utils.decode(base58Key); | |||||
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) { | |||||
throw new IllegalArgumentException("The specified file is not a private key file!"); | |||||
} | |||||
return decryptedPrivKeyBytes(keyBytes, pwdBytes); | |||||
} | |||||
public static boolean isPubKeyBytes(byte[] keyBytes) { | |||||
return BytesUtils.startsWith(keyBytes, PUB_KEY_FILE_MAGICNUM); | |||||
} | |||||
public static boolean isPrivKeyBytes(byte[] keyBytes) { | |||||
return BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM); | |||||
} | |||||
} |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<artifactId>crypto</artifactId> | <artifactId>crypto</artifactId> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
@@ -16,6 +16,9 @@ import org.bouncycastle.util.encoders.Base64; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.security.*; | import java.security.*; | ||||
import java.security.spec.InvalidKeySpecException; | |||||
import java.security.spec.PKCS8EncodedKeySpec; | |||||
import java.security.spec.X509EncodedKeySpec; | |||||
/** | /** | ||||
* @author zhanglin33 | * @author zhanglin33 | ||||
@@ -25,16 +28,18 @@ import java.security.*; | |||||
*/ | */ | ||||
public class CSRBuilder { | public class CSRBuilder { | ||||
private String BC = BouncyCastleProvider.PROVIDER_NAME; | |||||
private final String BC = BouncyCastleProvider.PROVIDER_NAME; | |||||
private PublicKey pubKey; | private PublicKey pubKey; | ||||
private PrivateKey privKey; | private PrivateKey privKey; | ||||
private String algoName; | private String algoName; | ||||
private int keyLength; | |||||
public void init() { | public void init() { | ||||
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | ||||
algoName = "SHA1withRSA"; | algoName = "SHA1withRSA"; | ||||
keyLength = 2048; | |||||
KeyPairGenerator generator; | KeyPairGenerator generator; | ||||
try { | try { | ||||
generator = KeyPairGenerator.getInstance("RSA", BC); | generator = KeyPairGenerator.getInstance("RSA", BC); | ||||
@@ -47,10 +52,11 @@ public class CSRBuilder { | |||||
} | } | ||||
} | } | ||||
public void init(String algoName, int KeyLength) { | |||||
public void init(String algoName, int keyLength) { | |||||
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | ||||
this.algoName = algoName; | |||||
this.algoName = algoName; | |||||
this.keyLength = keyLength; | |||||
KeyPairGenerator generator; | KeyPairGenerator generator; | ||||
KeyPair keyPair; | KeyPair keyPair; | ||||
@@ -60,34 +66,69 @@ public class CSRBuilder { | |||||
switch (hashAndSignature[1]) { | switch (hashAndSignature[1]) { | ||||
case "RSA": { | case "RSA": { | ||||
generator = KeyPairGenerator.getInstance("RSA", BC); | generator = KeyPairGenerator.getInstance("RSA", BC); | ||||
generator.initialize(KeyLength); | |||||
keyPair = generator.generateKeyPair(); | |||||
pubKey = keyPair.getPublic(); | |||||
privKey = keyPair.getPrivate(); | |||||
generator.initialize(keyLength); | |||||
break; | break; | ||||
} | } | ||||
case "SM2": { | case "SM2": { | ||||
generator = KeyPairGenerator.getInstance("EC", BC); | generator = KeyPairGenerator.getInstance("EC", BC); | ||||
if (KeyLength != 256) { | |||||
if (keyLength != 256) { | |||||
throw new CryptoException("SM3withSM2 with unsupported key length [" + | throw new CryptoException("SM3withSM2 with unsupported key length [" + | ||||
KeyLength +"] in CSR!"); | |||||
keyLength +"] in CSR!"); | |||||
} | } | ||||
generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1")); | generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1")); | ||||
keyPair = generator.generateKeyPair(); | |||||
pubKey = keyPair.getPublic(); | |||||
privKey = keyPair.getPrivate(); | |||||
break; | break; | ||||
} | } | ||||
default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with key length [" + | default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with key length [" + | ||||
KeyLength +"] in CSR!"); | |||||
keyLength +"] in CSR!"); | |||||
} | } | ||||
keyPair = generator.generateKeyPair(); | |||||
pubKey = keyPair.getPublic(); | |||||
privKey = keyPair.getPrivate(); | |||||
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { | } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { | ||||
throw new CryptoException(e.getMessage(), e); | throw new CryptoException(e.getMessage(), e); | ||||
} | } | ||||
} | } | ||||
public void init(String algoName, byte[] pubKeyBytes, byte[] privKeyBytes) { | |||||
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | |||||
this.algoName = algoName; | |||||
String[] hashAndSignature = algoName.split("with"); | |||||
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pubKeyBytes); | |||||
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privKeyBytes); | |||||
KeyFactory keyFactory; | |||||
try { | |||||
switch (hashAndSignature[1]) { | |||||
case "RSA": { | |||||
keyFactory = KeyFactory.getInstance("RSA"); | |||||
privKey = keyFactory.generatePrivate(privKeySpec); | |||||
pubKey = keyFactory.generatePublic(pubKeySpec); | |||||
keyLength = (pubKey.getEncoded().length < 4096 / 8)? 2048: 4096; | |||||
break; | |||||
} | |||||
case "SM2": { | |||||
keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); | |||||
privKey = keyFactory.generatePrivate(privKeySpec); | |||||
pubKey = keyFactory.generatePublic(pubKeySpec); | |||||
keyLength = 256; | |||||
break; | |||||
} | |||||
default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with the given key pair!"); | |||||
} | |||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) { | |||||
throw new CryptoException(e.getMessage(), e); | |||||
} | |||||
} | |||||
public String buildRequest(String countryName, String stateName, String cityName, | public String buildRequest(String countryName, String stateName, String cityName, | ||||
String organizationName, String departmentName, String domainName, | String organizationName, String departmentName, String domainName, | ||||
String emailName) { | String emailName) { | ||||
@@ -126,4 +167,12 @@ public class CSRBuilder { | |||||
public PrivateKey getPrivKey() { | public PrivateKey getPrivKey() { | ||||
return privKey; | return privKey; | ||||
} | } | ||||
public String getAlgoName() { | |||||
return algoName; | |||||
} | |||||
public int getKeyLength() { | |||||
return keyLength; | |||||
} | |||||
} | } |
@@ -25,6 +25,7 @@ public class CertParser { | |||||
private String sigAlgName; | private String sigAlgName; | ||||
private String userName; | private String userName; | ||||
private String issuerName; | private String issuerName; | ||||
private int keyLength; | |||||
private Date startTime; | private Date startTime; | ||||
private Date endTime; | private Date endTime; | ||||
@@ -71,6 +72,17 @@ public class CertParser { | |||||
sigAlgName = userCert.getSigAlgName(); | sigAlgName = userCert.getSigAlgName(); | ||||
issuerName = userCert.getIssuerX500Principal().getName(); | issuerName = userCert.getIssuerX500Principal().getName(); | ||||
userName = userCert.getSubjectX500Principal().getName(); | userName = userCert.getSubjectX500Principal().getName(); | ||||
switch (sigAlgName) { | |||||
case "SM3WITHSM2": { | |||||
keyLength = 256; | |||||
break; | |||||
} | |||||
case "SHA1WITHRSA": { | |||||
keyLength = (pubKey.getEncoded().length < 4096 / 8)? 2048: 4096; | |||||
break; | |||||
} | |||||
} | |||||
} | } | ||||
// certificate string in Base64 format | // certificate string in Base64 format | ||||
@@ -121,6 +133,10 @@ public class CertParser { | |||||
return issuerName; | return issuerName; | ||||
} | } | ||||
public int getKeyLength() { | |||||
return keyLength; | |||||
} | |||||
public Date getStartTime() { | public Date getStartTime() { | ||||
return startTime; | return startTime; | ||||
} | } | ||||
@@ -1,9 +1,13 @@ | |||||
package com.jd.blockchain.crypto.service.pki; | package com.jd.blockchain.crypto.service.pki; | ||||
import com.jd.blockchain.crypto.*; | import com.jd.blockchain.crypto.*; | ||||
import com.jd.blockchain.crypto.utils.CSRBuilder; | |||||
import com.jd.blockchain.crypto.utils.CertParser; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.security.*; | |||||
import java.util.Random; | import java.util.Random; | ||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.*; | import static com.jd.blockchain.crypto.CryptoAlgorithm.*; | ||||
@@ -125,4 +129,145 @@ public class SHA1WITHRSA2048SignatureFunctionTest { | |||||
resolvedSignatureDigest.getAlgorithm()); | resolvedSignatureDigest.getAlgorithm()); | ||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | ||||
} | } | ||||
@Test | |||||
public void testWithCSRAndCert() { | |||||
String countryName = "CN"; | |||||
String stateName = "Beijing"; | |||||
String cityName = "Beijing"; | |||||
String organizationName = "JD.com"; | |||||
String departmentName = "Blockchain Department"; | |||||
String domainName = "ledger.jd.com"; | |||||
String emailName = "zhanglin33@jd.com"; | |||||
String publicKeyStr = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c91e978897a36b" + | |||||
"30a57d265807441b0eff40c5572ecf029cd0cb2999b715edd2d5345c7b60c003075b1352629d03b943d08b25bfc5245" + | |||||
"a400f9ecbc1757394eac452d6316bf90cfcff5edfc427e277aa5266e89b1b2daa2e69dad5575515f49417c9ff332c83" + | |||||
"0dcd5537381f08e00b11123ad947bb11b18666d264ab5d8cdc92d0967fd7e0e6677746e2f01270d0594f74cda4e9d77" + | |||||
"4c6f3824499896bfb6424684af260d71b57a1366b741104fc647d9e38de055568daad60c116686e4afa1e9c83e9e30c" + | |||||
"7216e61353da2f75b2dde2c0ae870cf0ccc90490d1e22ecccbf3985d30933689847e6faf946993f930f83ac5b816075" + | |||||
"793a9a6df20727552a21be30203010001"; | |||||
String privateKeyStr = "308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100c91e" + | |||||
"978897a36b30a57d265807441b0eff40c5572ecf029cd0cb2999b715edd2d5345c7b60c003075b1352629d03b943d08" + | |||||
"b25bfc5245a400f9ecbc1757394eac452d6316bf90cfcff5edfc427e277aa5266e89b1b2daa2e69dad5575515f49417" + | |||||
"c9ff332c830dcd5537381f08e00b11123ad947bb11b18666d264ab5d8cdc92d0967fd7e0e6677746e2f01270d0594f7" + | |||||
"4cda4e9d774c6f3824499896bfb6424684af260d71b57a1366b741104fc647d9e38de055568daad60c116686e4afa1e" + | |||||
"9c83e9e30c7216e61353da2f75b2dde2c0ae870cf0ccc90490d1e22ecccbf3985d30933689847e6faf946993f930f83" + | |||||
"ac5b816075793a9a6df20727552a21be30203010001028201003975637e93300d8a2ee573e47762f6461117cca96d46" + | |||||
"982cfc1be6ed3318f142a845d6dc2ad680a703d69fd56b9d6a3b1d23fbeb6f63c4e303736f2bfca5c2585631825f494" + | |||||
"534783d6f3a07bd0b5efbcaa1faf7814ac9118c8d8820f4be9a8b0ac6db819fc86b538bf284369d9f009a667668a82d" + | |||||
"224f7122041eddb492ef5b02d462aa11bc550bf3785a5d7538043586cfb0cd5c313a4746f22a5d4a89a412b279a7517" + | |||||
"176b1858a9677a1a60605aa0b2a7d260cf2e9e23a0e67c4a23ac046c62973239e84874c3695cc3f34073a62bd50b597" + | |||||
"ee06092a93fa6e41303ab4d2293ffad4c8db06e6516ae0a26a4d681305c3b7d535b540a638ca6cff1ce483750281810" + | |||||
"0e39967c5b287bd319b448255a1033591c74f4d688eb71f89a674cdb1be999e9abcf40e6b7f0bb3054262d7625002da" + | |||||
"7d34e56055ee130b66d682a0b9f8ea240a7e2dd1ff3f4b32f3bd352ba0a5dffc0315da34922493c267597787222213b" + | |||||
"f87d99fbd2a809c2647a1937cd1e303d746373db7c409a2ef33f8c06bb838bc612702818100e2374c71db5f0b4a199f" + | |||||
"f9d646a1785a84383a14aceb506f515b380c69ff45b51d0e941f55f0a234d8a3ee30bed656142bb5b985e462c44d234" + | |||||
"cfd424ecd6ca5fc70503862978ffe42b45bd698a99091d6fc65e2d85652e0ef56c52e8e05a6c5e879922c1d794e22f3" + | |||||
"51998217b5c6637a6abb716bf90cd1f23a2eedcdfface50281805d28a872224e2f2183e539d7e4ccd47b73f240c4004" + | |||||
"e72493c69e8dbcd2141eb22565f249edee20ad00e770c95a5655b0470b2cad964d030eab293292bfa62802cff824a10" + | |||||
"d52de8d8545024346106dd186fb53ef05bcea1d0dbfce2fac1cc8ec583fdc0ccdd9d498a983cea081ac55dc734aae84" + | |||||
"1ed802d6caf0e285c88b6d702818068b2a752daf1364c6967bd3e0b1a98956c3489cd1feb19232c4847bc97226aa4d4" + | |||||
"79f6dc39ee51649c0fe321f471470db6dd38ac5b73caded8c3bd437f2d5c67c65a450693bb0a0de7d989d7dc783e4d0" + | |||||
"16f77c871d02233b1123bd8bc2aa97157934cafd6445a819a93ddb4743cd141215b5cbdb5f7629398c48d0bcb17d671" + | |||||
"028181009282554329b89bcb2236a7e2a5bff53627e3ca7cc792d65236085741bc62a3f5767654722af561eff175664" + | |||||
"1af60e3d3959f63f0fec00cb29443ffca4ff751a76ecc6fa192ebe08ec9f643b9bb0d11bc90c1e850f0528ef223ea5f" + | |||||
"e4b4c107cc3a9eb26e6b84d74d87acbf7cc760cd788cbc30f95f8399077b25cdd924604c01"; | |||||
String expectedCSR = "MIIC4jCCAcoCAQAwgZwxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW" + | |||||
"5nMQ8wDQYDVQQKDAZKRC5jb20xHjAcBgNVBAsMFUJsb2NrY2hhaW4gRGVwYXJ0bWVudDEWMBQGA1UEAwwNbGVkZ2VyLmpkL" + | |||||
"mNvbTEgMB4GCSqGSIb3DQEJARYRemhhbmdsaW4zM0BqZC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJ" + | |||||
"HpeIl6NrMKV9JlgHRBsO/0DFVy7PApzQyymZtxXt0tU0XHtgwAMHWxNSYp0DuUPQiyW/xSRaQA+ey8F1c5TqxFLWMWv5DPz" + | |||||
"/Xt/EJ+J3qlJm6JsbLaouadrVV1UV9JQXyf8zLIMNzVU3OB8I4AsREjrZR7sRsYZm0mSrXYzcktCWf9fg5md3RuLwEnDQWU" + | |||||
"90zaTp13TG84JEmYlr+2QkaEryYNcbV6E2a3QRBPxkfZ443gVVaNqtYMEWaG5K+h6cg+njDHIW5hNT2i91st3iwK6HDPDMy" + | |||||
"QSQ0eIuzMvzmF0wkzaJhH5vr5Rpk/kw+DrFuBYHV5Oppt8gcnVSohvjAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEALKHw" + | |||||
"BrlppbN+CSJwHxO99rv2XVD7L8lwwiMqdMzoNHxZUoob4AcGS3Iyxy6obX8fZh7DCA4nN0AmvrJCmWD3hCLclWKlwXTwvFe" + | |||||
"WIeB4xEB9MVPV6/Hs/QaI9Rjhd+O/Alfzov8y+KyYHEWmwxHj2RtQm1ZeulELzMvRjsqP+m5tOM1hLnPMU+AF1tZ9Fc7Jbm" + | |||||
"7Dwh6TAPpmaH1aVbHsnlZyCp8K4nMozVogcXJqg3qsbeJ6c/TofL0fURqiTJxLKMC0aD0TwVcNwDWEmc8cpqGheG1g6UF5l" + | |||||
"QBpeR2Br4f3LXJgr1Op1RxRy6I+X7h1IL38Q3jAOoU4y04O/+an7g=="; | |||||
String expectedUserCert = "MIIERjCCAy6gAwIBAgIFIChmYJgwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVB" + | |||||
"AoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4X" + | |||||
"DTE5MDgyODA2MzEyNVoXDTIxMDgyODA2MzEyNVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTE" + | |||||
"RMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MT" + | |||||
"IyMjkyOTVANTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMkel4iXo2swpX0mWAdEGw7/QMVXLs8CnNDLKZm3F" + | |||||
"e3S1TRce2DAAwdbE1JinQO5Q9CLJb/FJFpAD57LwXVzlOrEUtYxa/kM/P9e38Qn4neqUmbomxstqi5p2tVXVRX0lBfJ/zMs" + | |||||
"gw3NVTc4HwjgCxESOtlHuxGxhmbSZKtdjNyS0JZ/1+DmZ3dG4vAScNBZT3TNpOnXdMbzgkSZiWv7ZCRoSvJg1xtXoTZrdBE" + | |||||
"E/GR9njjeBVVo2q1gwRZobkr6HpyD6eMMchbmE1PaL3Wy3eLArocM8MzJBJDR4i7My/OYXTCTNomEfm+vlGmT+TD4OsW4Fg" + | |||||
"dXk6mm3yBydVKiG+MCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GC" + | |||||
"GCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEw" + | |||||
"L6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjY2NTAuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQ" + | |||||
"UOTy45HymVDivPwA83lRoMpShasQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQ" + | |||||
"A7NFkDMV1mRV/07DJUdZJzvkm+QihhpLp7D2dUblCCEt0jjY5RdLiWG7HvJnlPTThiSkiejEO0Fy1cQzA5jYRhwp+70X8X9" + | |||||
"bt5jEBP/V4PyRXKKEvKZMdppLIeVI6rZk/gJzPh2FQYv3qWaINilxLOBP8Qa0kdMBwo6D6/MYwnSGv5zP4NLFUysLUJiKoM" + | |||||
"lAzEQSPNnkYRX6nogpkdN91/xgH3GA7fiihrjm5oxMAupCli9LQqvlUvRtv5EKIN9c+ixCAYFagG9IIjMDXbDne77n15i01" + | |||||
"420N8sjfTlr9v3W0v1gBSzjzFOT+TTTUtrjfO/Vm8iqq+z22QKIXgYjSF"; | |||||
String issuerCert = | |||||
"-----BEGIN CERTIFICATE-----\n" + | |||||
"MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" + | |||||
"VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" + | |||||
"QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" + | |||||
"NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" + | |||||
"bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" + | |||||
"RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" + | |||||
"jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" + | |||||
"jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" + | |||||
"bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" + | |||||
"RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" + | |||||
"0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" + | |||||
"t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" + | |||||
"aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" + | |||||
"Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" + | |||||
"MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" + | |||||
"AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" + | |||||
"3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" + | |||||
"/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" + | |||||
"/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" + | |||||
"fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" + | |||||
"OMRZvB7FRyE9IfwKApngcZbA5g==\n" + | |||||
"-----END CERTIFICATE-----"; | |||||
byte[] rawPublicKeyBytes = Hex.decode(publicKeyStr); | |||||
byte[] rawPrivateKeyBytes = Hex.decode(privateKeyStr); | |||||
CSRBuilder builder = new CSRBuilder(); | |||||
builder.init("SHA1withRSA", rawPublicKeyBytes, rawPrivateKeyBytes); | |||||
String csr = builder.buildRequest(countryName,stateName,cityName, | |||||
organizationName,departmentName,domainName, | |||||
emailName); | |||||
assertEquals(expectedCSR,csr); | |||||
CertParser parser = new CertParser(); | |||||
parser.parse(expectedUserCert,issuerCert); | |||||
PublicKey rawPublicKeyInCert = parser.getPubKey(); | |||||
// check that the public key in inputs and the public key in certificate are consistent | |||||
assertArrayEquals(rawPublicKeyBytes, rawPublicKeyInCert.getEncoded()); | |||||
String algoName = parser.getSigAlgName(); | |||||
int keyLength = parser.getKeyLength(); | |||||
String length = String.valueOf(keyLength); | |||||
String algo = (algoName.contains("RSA")? (algoName + length).toUpperCase(): algoName.toUpperCase()); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm(algo); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
PubKey pubKey = new PubKey(algorithm, rawPublicKeyBytes); | |||||
PrivKey privKey = new PrivKey(algorithm, rawPrivateKeyBytes); | |||||
// signTest | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
SignatureDigest signature = signatureFunction.sign(privKey, data); | |||||
assertTrue(signatureFunction.verify(signature, pubKey, data)); | |||||
} | |||||
} | } |
@@ -1,9 +1,13 @@ | |||||
package com.jd.blockchain.crypto.service.pki; | package com.jd.blockchain.crypto.service.pki; | ||||
import com.jd.blockchain.crypto.*; | import com.jd.blockchain.crypto.*; | ||||
import com.jd.blockchain.crypto.utils.CSRBuilder; | |||||
import com.jd.blockchain.crypto.utils.CertParser; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.security.PublicKey; | |||||
import java.util.Random; | import java.util.Random; | ||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | ||||
@@ -125,4 +129,186 @@ public class SHA1WITHRSA4096SignatureFunctionTest { | |||||
resolvedSignatureDigest.getAlgorithm()); | resolvedSignatureDigest.getAlgorithm()); | ||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | ||||
} | } | ||||
@Test | |||||
public void testWithCSRAndCert() { | |||||
String countryName = "CN"; | |||||
String stateName = "Beijing"; | |||||
String cityName = "Beijing"; | |||||
String organizationName = "JD.com"; | |||||
String departmentName = "Blockchain Department"; | |||||
String domainName = "ledger.jd.com"; | |||||
String emailName = "zhanglin33@jd.com"; | |||||
String publicKeyStr = "30820222300d06092a864886f70d01010105000382020f003082020a0282020100b40edee83b609e" + | |||||
"aa001f2496f95d2f3302513306ec9a8e7fce0d2e141fce7ee357a7465314c3f5f4b08cb6c95803c368ddbfedba483cb" + | |||||
"5c45914037ceee5783fc971a12ef9b0e4158dc379b59499eee629324a9beb350c4c10e50837345be128b91f43a03381" + | |||||
"758bbefe41c45712e4b5fdd5bde780167283706b24e37dd753db65b4c6b3e49cd8be825665d9a29a24b77e76473df02" + | |||||
"2327873555aa33ba2ffcc766cbefedc46ec868d10f817822540eaf5754c074dd6d428355ce24a058a4c9ce41e48aad5" + | |||||
"92e7955cf93d779d03d3acf25ae271346a9e4255e4ed902ae016032b04efbee98f43cd767653e089b37540e537aede9" + | |||||
"dbc04f8f1a858b2764b9eedac80b6a8da5ff02aab4be94e071c70718fde7227cdefec31600a1c55bac16f4de9dea8ab" + | |||||
"7824c1ec783b818dfe005f040a3f6872b1c7a6c31a66c1b06eb8d872a23d1b4fdadf9eed58f93b2a2bc145638a79a81" + | |||||
"904d39b22128ced18a2556c21888ed1ec8ad59bd6764f1ea16eb7f3574c53166f0827b5072d23017bd725adeb63eeb2" + | |||||
"29a4e78d4d7426e936753902bb51e3cd90630314f4ab41272a9e36cb668b2ba9c2ebc02e9ef0c377c88482e839f2f4d" + | |||||
"5c8efcfbe1280e52c6bdf80aa487ae03ff9dd9fd981f78172bc1141ce6031b0b8915658d830c696662507d3cf4ddba8" + | |||||
"7daabf97c15cbef58b15e84f16f879328c7c65076d94fc6b4514549831850203010001"; | |||||
String privateKeyStr = "30820942020100300d06092a864886f70d01010105000482092c308209280201000282020100b40e" + | |||||
"dee83b609eaa001f2496f95d2f3302513306ec9a8e7fce0d2e141fce7ee357a7465314c3f5f4b08cb6c95803c368ddb" + | |||||
"fedba483cb5c45914037ceee5783fc971a12ef9b0e4158dc379b59499eee629324a9beb350c4c10e50837345be128b9" + | |||||
"1f43a03381758bbefe41c45712e4b5fdd5bde780167283706b24e37dd753db65b4c6b3e49cd8be825665d9a29a24b77" + | |||||
"e76473df022327873555aa33ba2ffcc766cbefedc46ec868d10f817822540eaf5754c074dd6d428355ce24a058a4c9c" + | |||||
"e41e48aad592e7955cf93d779d03d3acf25ae271346a9e4255e4ed902ae016032b04efbee98f43cd767653e089b3754" + | |||||
"0e537aede9dbc04f8f1a858b2764b9eedac80b6a8da5ff02aab4be94e071c70718fde7227cdefec31600a1c55bac16f" + | |||||
"4de9dea8ab7824c1ec783b818dfe005f040a3f6872b1c7a6c31a66c1b06eb8d872a23d1b4fdadf9eed58f93b2a2bc14" + | |||||
"5638a79a81904d39b22128ced18a2556c21888ed1ec8ad59bd6764f1ea16eb7f3574c53166f0827b5072d23017bd725" + | |||||
"adeb63eeb229a4e78d4d7426e936753902bb51e3cd90630314f4ab41272a9e36cb668b2ba9c2ebc02e9ef0c377c8848" + | |||||
"2e839f2f4d5c8efcfbe1280e52c6bdf80aa487ae03ff9dd9fd981f78172bc1141ce6031b0b8915658d830c696662507" + | |||||
"d3cf4ddba87daabf97c15cbef58b15e84f16f879328c7c65076d94fc6b451454983185020301000102820200063fece" + | |||||
"3452a579f817513454d3efb842afcac077dbf689a4d89de13533e4cdfb1bb6be0b6dc0d65b29a13bf1dd7b598e67782" + | |||||
"b6204b4128e149a54c59136c6ed45c661296169a78180d54a46595c939c26ccd33a7c095de6f08b01610726ef885a26" + | |||||
"cebbad5efc14bbe1204d15be5c5de5b64a5cc279b4e6e20bded4a8126973b2ac0e9de11c6a1282f7d060693909a30e0" + | |||||
"c49cc500bedd38ed99c18830a26dd39f772aabf527410d54ed338db022d674f21f1332d3b5d5f67234a58a97300d130" + | |||||
"aed0d46effc2b4e4895665934188d0c75749e26ca5b97645957989530657b332b4ef202b3d70fe2e07d0d526240fbe1" + | |||||
"68e320357be0f54e18008a233a8137e23ca1c54074b31c57eebee49bf2f1c66ea97a2c846a8d26680b97e1240d6763e" + | |||||
"60bcd8d696c806362b18bf0504a39e4d465a9548091dbe97c36f6d8e038d95a72c0a88ff524dc81fe0ed2afd69f4251" + | |||||
"1a90687a4c632c812234a19a7312b2dea3fcd4515800eca700733b0f83509184fe8d3cd21385f0ef0cec37c433d354f" + | |||||
"aed61662a62902c8708c81e2af20898f649c1bafd600baa0409c943cf82bc90ea20a8972da7ab3a252f4f08df2509de" + | |||||
"e1dacfe787eef4d60c0c92ec7a3c6277d7be39deed7704ac721d8efd138a410d632a32535142cf977b09d9fb680bc96" + | |||||
"c538c00440d5e1ed71f8510e6524e564d69a24d03f1a9a0c326b421e32550801c890282010100e8d72f8f1fbeada724" + | |||||
"3e6df25337a2e7fc43e3d4f39877f89abb3b5e453f20f339a1f35e0a2847122f0bd835e6b43fd276f447da04f85cfca" + | |||||
"0fa8bf49b313239e36f9595ef1bfb9b8247bf01cc407dfc444421161a5b2e96d4d1d90cea185945e9447d21a2d8a461" + | |||||
"f43dff9ba58043feeb49552a3bf2472eea59b2aa8631048c76a15898065be0ef957d4802c827e30339d66ad7aed5851" + | |||||
"a5896f12d33f45800dcb10859531c590af7a75e9fa81f1d937a287fb6b066d58720584af2ae161e083681655ae77f48" + | |||||
"34bfe0accf1d12bbdd8c2644f78b207cfcb2dedf9fe7d29e1ae5c2a5623f5a1770db27d2636450c79fd39bce39f009b" + | |||||
"598e0298e1f77bf8d3d0282010100c5f7af9258a42da93204cecb71c544397bc16691cf0d41308fbd3b88eca7d101d1" + | |||||
"377dfe3b7e66707d3e5543b21033ab6c5b0de577740c6e335f512eeb2a839c3f2baeca4ce80e3fbd8fb93fa983e1719" + | |||||
"5c5fee63bc163df334a80f2767871e3434adc0bc7030dea44fce414a08da7e918e6f030cfb20b2d29033e9ef1be3e08" + | |||||
"ef1f50df0c9325a20ff01d0b7a06761403ae3498aea8bad93110d61a6386d470e630990029e2cb098de40fafa330911" + | |||||
"6c3c6de180b7fa41ae14553e891148ab53e970ce372b1777826983baaccac08290e343761d8daa2505f1dc45b8511a3" + | |||||
"6e2d0909237be9ae7ebbaa00b31de1224f32959e4e6f3428140ca8e1e5580789e902820100674075609c8d2be880940" + | |||||
"6a17cf1a1160ab1f8684895862e023fa0f60ef30da38e1d1914cca04bd3ee74ec2e0ade47a70705108fc7c0734bbbff" + | |||||
"1eed1b9cd74f00624d0d2df954bc032bd9b1ec6774f6d736f70d1c26ef2407bffee65130f6f59f99b57ba3013af40d2" + | |||||
"12926565fe8c734835276e61a6c228bddb6f3138acd1f94c3bbcbbe9623cb5a9931c3ba0aa60a9a2d5137cfd9f3aa59" + | |||||
"3aa63c8b5b8162f07ab8df1391f092827bffe400e3bb73d8a9f8e88495357f3482b2c9a7153bc01c9b88dca4e7b6975" + | |||||
"db73e2aa213daa7462cfa4c63afc67d30bcd0a1d2657da323dc0b06e45d09240cab3e0ac1436922a0ede8a79ca0519d" + | |||||
"375a7621d23269690282010100bbc1299716d2bf2b94f0d260494ada65da6596adfb3d8af24fa11d71c36175eccf4c5" + | |||||
"e065cce88c16f474afea546907aa88dc3243aa2a9976ac99fe96bc82a8269b738534d9558ce432ea87724829bb26a66" + | |||||
"1a56a99dc4e6cf727dd17762cc40ca759934e24e9747f49e14832bb2ade97960adb4dd86f2eaa5d719f10d3d6d00742" + | |||||
"9b33d98638671a9c40507f9775f4da41ff86a465c68b9ccbb371458086c3b9755c8064bb378f55ac94dc73a72b96869" + | |||||
"cd969e1f69b36e7af091a024d8e2a4faf3af999811904937f171c58fd028fd272786cf1a286180f074fee1fdd6b8b5a" + | |||||
"9a8c42e0f3b95ef4474fbace54dbc887865467b0524e64dfda3be7b117e34e1028201001a7e846231c34400c1f704e7" + | |||||
"fec6e46c87d61f269b71942bc9cc72005ba30eea3db5d0e5b0b754f7a00b96c883399982b5b3a9916765c5ed9129e44" + | |||||
"a791ce6892f85758c637bc040da132b8f0cd0ac36ba3aae9334414a77f0b50c0aa03643bfd59b9a621342a4807e46fc" + | |||||
"52a5a12fd3ff6762e181c40c2baf3653043c836b14700463af5d68a2a2897897edb5f217d655d5bcd24e7910062f40e" + | |||||
"00f19e2f94b45efbbf60cbf734830756baf72dcfca8d2858ca5df63336999474945f3744a96e4ce23f9067bbca849ef" + | |||||
"1048cba3a4aad73ed73b0fcd8c2e9f6d06aa768548d7107aa58d9d296f853543f6569e4dd33270540d983460773794f" + | |||||
"e9196fc5a54cd"; | |||||
String expectedCSR = "MIIE4jCCAsoCAQAwgZwxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW" + | |||||
"5nMQ8wDQYDVQQKDAZKRC5jb20xHjAcBgNVBAsMFUJsb2NrY2hhaW4gRGVwYXJ0bWVudDEWMBQGA1UEAwwNbGVkZ2VyLmpkL" + | |||||
"mNvbTEgMB4GCSqGSIb3DQEJARYRemhhbmdsaW4zM0BqZC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0" + | |||||
"Dt7oO2CeqgAfJJb5XS8zAlEzBuyajn/ODS4UH85+41enRlMUw/X0sIy2yVgDw2jdv+26SDy1xFkUA3zu5Xg/yXGhLvmw5BW" + | |||||
"Nw3m1lJnu5ikySpvrNQxMEOUINzRb4Si5H0OgM4F1i77+QcRXEuS1/dW954AWcoNwayTjfddT22W0xrPknNi+glZl2aKaJL" + | |||||
"d+dkc98CIyeHNVWqM7ov/Mdmy+/txG7IaNEPgXgiVA6vV1TAdN1tQoNVziSgWKTJzkHkiq1ZLnlVz5PXedA9Os8lricTRqn" + | |||||
"kJV5O2QKuAWAysE777pj0PNdnZT4ImzdUDlN67enbwE+PGoWLJ2S57trIC2qNpf8CqrS+lOBxxwcY/ecifN7+wxYAocVbrB" + | |||||
"b03p3qireCTB7Hg7gY3+AF8ECj9ocrHHpsMaZsGwbrjYcqI9G0/a357tWPk7KivBRWOKeagZBNObIhKM7RiiVWwhiI7R7Ir" + | |||||
"Vm9Z2Tx6hbrfzV0xTFm8IJ7UHLSMBe9clretj7rIppOeNTXQm6TZ1OQK7UePNkGMDFPSrQScqnjbLZosrqcLrwC6e8MN3yI" + | |||||
"SC6Dny9NXI78++EoDlLGvfgKpIeuA/+d2f2YH3gXK8EUHOYDGwuJFWWNgwxpZmJQfTz03bqH2qv5fBXL71ixXoTxb4eTKMf" + | |||||
"GUHbZT8a0UUVJgxhQIDAQABoAAwDQYJKoZIhvcNAQEFBQADggIBAKowJTG9mZLbDHRndmDUd7PWrq1AiCdk6DStV39B/REF" + | |||||
"OrMYcW9X4Ak69fhXQDtD4gu2lKtumDY0oJ8xleM2FHUSzdooTWb7P/QtCIBy27sH6nvlefRWi7ngSTNJlDmwgr0l07UzZU1" + | |||||
"Yl/ZULn0XlNAFal+qt+4ZNdiulNwkL6IofXV/8vqOeQw5iICDBYHItyY/mqD8IIaClVd8yNpEuE/W9GdJIDNXQjpug+BxL/" + | |||||
"FbjAs6P3ZzJboedJE5urbru2jjb7atl3w/eDo4r6+XNSD8d1PgVmVhzN2WpUWsZNeH2jd9AA6436GjsBssgSRKEc3FTJ+lO" + | |||||
"0Jw2d8GewXXkIv8CT4L3BFwqZhGQt27wlb87+W4dIC05JIaJx52869dvu1ky1CL73GROXeS8rVYJsPwVmK2xy3QTaeHGEQh" + | |||||
"kiVNeV1cc3mll2z7fgbkjPD8zDNBWUdzSXQMzecY1CBD02iz6LaHfvkI7gXXoiIf1cJrnLtYhv3lG45jKr0E45/Wn7oXmYk" + | |||||
"RM4/zHO4KnY7Pp3b3QTgkRJaPnZiG7aiCrdnTIopDSGpTWSPWDLjgwgaCPPz5Pd2Fk+SAE98o7Cu8O0vxMASpd4liaedASE" + | |||||
"n6hnrvcTkFLLG2ecZzJZ0aEqPi4es0FqlqVZrLPH2UYpECgfhkGQQKAx4eRTAZFhz1GSkd"; | |||||
String expectedUserCert = "MIIFRjCCBC6gAwIBAgIFIChmYWIwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVB" + | |||||
"AoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4X" + | |||||
"DTE5MDgyODA4MDAxMVoXDTIxMDgyODA4MDAxMVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTE" + | |||||
"RMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MT" + | |||||
"IyMjkyOTVANzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQO3ug7YJ6qAB8klvldLzMCUTMG7JqOf84NLhQfz" + | |||||
"n7jV6dGUxTD9fSwjLbJWAPDaN2/7bpIPLXEWRQDfO7leD/JcaEu+bDkFY3DebWUme7mKTJKm+s1DEwQ5Qg3NFvhKLkfQ6Az" + | |||||
"gXWLvv5BxFcS5LX91b3ngBZyg3BrJON911PbZbTGs+Sc2L6CVmXZopokt352Rz3wIjJ4c1Vaozui/8x2bL7+3Ebsho0Q+Be" + | |||||
"CJUDq9XVMB03W1Cg1XOJKBYpMnOQeSKrVkueVXPk9d50D06zyWuJxNGqeQlXk7ZAq4BYDKwTvvumPQ812dlPgibN1QOU3rt" + | |||||
"6dvAT48ahYsnZLnu2sgLao2l/wKqtL6U4HHHBxj95yJ83v7DFgChxVusFvTeneqKt4JMHseDuBjf4AXwQKP2hyscemwxpmw" + | |||||
"bBuuNhyoj0bT9rfnu1Y+TsqK8FFY4p5qBkE05siEoztGKJVbCGIjtHsitWb1nZPHqFut/NXTFMWbwgntQctIwF71yWt62Pu" + | |||||
"simk541NdCbpNnU5ArtR482QYwMU9KtBJyqeNstmiyupwuvALp7ww3fIhILoOfL01cjvz74SgOUsa9+Aqkh64D/53Z/Zgfe" + | |||||
"BcrwRQc5gMbC4kVZY2DDGlmYlB9PPTduofaq/l8FcvvWLFehPFvh5Mox8ZQdtlPxrRRRUmDGFAgMBAAGjgfUwgfIwHwYDVR" + | |||||
"0jBBgwFoAU/Au8RJoOMaGDqYGHJx4FQsa/VvgwSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwO" + | |||||
"i8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vMjEwLjc0LjQyLjMvT0NB" + | |||||
"MTEvUlNBL2NybDI2NjU1LmNybDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFBl1Gmb89bqbEKyFcTU3eOY/5NmKMB0GA1UdJQQ" + | |||||
"WMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEADEU//9rnWN1s3/ariMHIUmgzRUdz3fWYiDRzGC" + | |||||
"mcnnETlXDstGmoYmwCM+QwHw6cyKXkwkg9zV7c7CgM471ZuF00gq115d432Ps3RXGCpfQ2fn3gs+91ky/YqJOOyBb8KL0IP" + | |||||
"r/Zh56/y3XX0gORn4GLqaj+oVZrFcmKrPtVhySlXNiD5BRMq39mUbuLBweGsgNVQ9VxiWc8ZBGjlJ6OVsngbvWrtl3zgkKb" + | |||||
"X9lhr8Bxq3G+jOV8jvr1Dkn4a65g2TWcFquxmPvRc5UwN29CimbC7RViCL3Jp+zrGasqbjycuqu5eSXb6gG4/aV0/K9yn5k" + | |||||
"YlZMIBlbsXSEi5J26pg=="; | |||||
String issuerCert = | |||||
"-----BEGIN CERTIFICATE-----\n" + | |||||
"MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" + | |||||
"VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" + | |||||
"QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" + | |||||
"NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" + | |||||
"bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" + | |||||
"RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" + | |||||
"jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" + | |||||
"jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" + | |||||
"bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" + | |||||
"RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" + | |||||
"0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" + | |||||
"t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" + | |||||
"aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" + | |||||
"Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" + | |||||
"MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" + | |||||
"AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" + | |||||
"3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" + | |||||
"/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" + | |||||
"/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" + | |||||
"fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" + | |||||
"OMRZvB7FRyE9IfwKApngcZbA5g==\n" + | |||||
"-----END CERTIFICATE-----"; | |||||
byte[] rawPublicKeyBytes = Hex.decode(publicKeyStr); | |||||
byte[] rawPrivateKeyBytes = Hex.decode(privateKeyStr); | |||||
CSRBuilder builder = new CSRBuilder(); | |||||
builder.init("SHA1withRSA", rawPublicKeyBytes, rawPrivateKeyBytes); | |||||
String csr = builder.buildRequest(countryName,stateName,cityName, | |||||
organizationName,departmentName,domainName, | |||||
emailName); | |||||
assertEquals(expectedCSR,csr); | |||||
CertParser parser = new CertParser(); | |||||
parser.parse(expectedUserCert,issuerCert); | |||||
PublicKey rawPublicKeyInCert = parser.getPubKey(); | |||||
// check that the public key in inputs and the public key in certificate are consistent | |||||
assertArrayEquals(rawPublicKeyBytes, rawPublicKeyInCert.getEncoded()); | |||||
String algoName = parser.getSigAlgName(); | |||||
int keyLength = parser.getKeyLength(); | |||||
String length = String.valueOf(keyLength); | |||||
String algo = (algoName.contains("RSA")? (algoName + length).toUpperCase(): algoName.toUpperCase()); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm(algo); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
PubKey pubKey = new PubKey(algorithm, rawPublicKeyBytes); | |||||
PrivKey privKey = new PrivKey(algorithm, rawPrivateKeyBytes); | |||||
// signTest | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
SignatureDigest signature = signatureFunction.sign(privKey, data); | |||||
assertTrue(signatureFunction.verify(signature, pubKey, data)); | |||||
} | |||||
} | } |
@@ -1,9 +1,13 @@ | |||||
package com.jd.blockchain.crypto.service.pki; | package com.jd.blockchain.crypto.service.pki; | ||||
import com.jd.blockchain.crypto.*; | import com.jd.blockchain.crypto.*; | ||||
import com.jd.blockchain.crypto.utils.CSRBuilder; | |||||
import com.jd.blockchain.crypto.utils.CertParser; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.security.PublicKey; | |||||
import java.util.Random; | import java.util.Random; | ||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | ||||
@@ -270,4 +274,80 @@ public class SM3WITHSM2SignatureFunctionTest { | |||||
resolvedSignatureDigest.getAlgorithm()); | resolvedSignatureDigest.getAlgorithm()); | ||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | ||||
} | } | ||||
@Test | |||||
public void testWithCSRAndCert() { | |||||
String publicKeyStr = "3059301306072a8648ce3d020106082a811ccf5501822d03420004aa6586478be879504fdd02892f" + | |||||
"b4cf2bdb3d96a316f41ff7bcadfabef4ea836678984f9ba6931a609391426ca7164592f5fccd062be56fc32b3eec3a5" + | |||||
"0400971"; | |||||
String privateKeyStr = "308193020100301306072a8648ce3d020106082a811ccf5501822d0479307702010104207abd2953" + | |||||
"84f193abe4f3715c26bc15225061f007131755d94ca12c7e0ce0b3a0a00a06082a811ccf5501822da14403420004aa6" + | |||||
"586478be879504fdd02892fb4cf2bdb3d96a316f41ff7bcadfabef4ea836678984f9ba6931a609391426ca7164592f5" + | |||||
"fccd062be56fc32b3eec3a50400971"; | |||||
String expectedUserCert = "MIICwjCCAmWgAwIBAgIFIChnMlIwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UEC" + | |||||
"gwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTEx" + | |||||
"MB4XDTE5MDgyODA4MTUzNloXDTIxMDgyODA4MTUzNloweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0E" + | |||||
"xMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMT" + | |||||
"g2MTIyMjkyOTVAODBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABKplhkeL6HlQT90CiS+0zyvbPZajFvQf97yt+r706oNme" + | |||||
"JhPm6aTGmCTkUJspxZFkvX8zQYr5W/DKz7sOlBACXGjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8w" + | |||||
"SAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh" + | |||||
"0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDI0OTkuY3JsMAsGA1UdDwQEAw" + | |||||
"ID6DAdBgNVHQ4EFgQU07tMtbs5PWkwN33OQVH116xd1kowHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBH" + | |||||
"M9VAYN1BQADSQAwRgIhAPuuInppVhugw6EIG4wgkouxX/MX2dTLe478wx7LFXSQAiEAneiz51vrurICNCfeecaBHgzaj7+3" + | |||||
"kmrdIZJBoxYGbso="; | |||||
String issuerCert = | |||||
"-----BEGIN CERTIFICATE-----\n" + | |||||
"MIICTzCCAfOgAwIBAgIKJFSZ4SRVDndYUTAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" + | |||||
"BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" + | |||||
"dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" + | |||||
"MDU0ODQ3WhcNMzIwODI0MDU0ODQ3WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" + | |||||
"Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" + | |||||
"DBNDRkNBIFRFU1QgU00yIE9DQTExMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" + | |||||
"L1mx4wriQUojGsIkNL14kslv9nwiqsiVpELOZauzghrbccNlPYKNYKZOCvXwIIqU\n" + | |||||
"9QY02d4weqKqo/JMcNsKEaOBmDCBlTAfBgNVHSMEGDAWgBS12JBvXPDYM9JjvX6y\n" + | |||||
"w43GTxJ6YTAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly8y\n" + | |||||
"MTAuNzQuNDIuMy90ZXN0cmNhL1NNMi9jcmwxLmNybDALBgNVHQ8EBAMCAQYwHQYD\n" + | |||||
"VR0OBBYEFL6mfk09fI+gVebBLwkuLCBDs0J/MAwGCCqBHM9VAYN1BQADSAAwRQIh\n" + | |||||
"AKuk7s3eYCZDck5NWU0eNQmLhBN/1zmKs517qFrDrkJWAiAP4cVfLtdza/OkwU9P\n" + | |||||
"PrIDl+E4aL3FypntFXHG3T+Keg==\n" + | |||||
"-----END CERTIFICATE-----"; | |||||
byte[] rawPublicKeyBytes = Hex.decode(publicKeyStr); | |||||
byte[] rawPrivateKeyBytes = Hex.decode(privateKeyStr); | |||||
CSRBuilder builder = new CSRBuilder(); | |||||
builder.init("SM3withSM2", rawPublicKeyBytes, rawPrivateKeyBytes); | |||||
CertParser parser = new CertParser(); | |||||
parser.parse(expectedUserCert,issuerCert); | |||||
PublicKey rawPublicKeyInCert = parser.getPubKey(); | |||||
// check that the public key in inputs and the public key in certificate are consistent | |||||
assertArrayEquals(rawPublicKeyBytes, rawPublicKeyInCert.getEncoded()); | |||||
String algoName = parser.getSigAlgName(); | |||||
int keyLength = parser.getKeyLength(); | |||||
String length = String.valueOf(keyLength); | |||||
String algo = (algoName.contains("RSA")? (algoName + length).toUpperCase(): algoName.toUpperCase()); | |||||
CryptoAlgorithm algorithm = Crypto.getAlgorithm(algo); | |||||
assertNotNull(algorithm); | |||||
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||||
PubKey pubKey = new PubKey(algorithm, rawPublicKeyBytes); | |||||
PrivKey privKey = new PrivKey(algorithm, rawPrivateKeyBytes); | |||||
// signTest | |||||
byte[] data = new byte[1024]; | |||||
Random random = new Random(); | |||||
random.nextBytes(data); | |||||
SignatureDigest signature = signatureFunction.sign(privKey, data); | |||||
assertTrue(signatureFunction.verify(signature, pubKey, data)); | |||||
} | |||||
} | } |
@@ -43,7 +43,8 @@ public class CertParserTest { | |||||
String userCert = "MIIEQDCCAyigAwIBAgIFICdVYzEwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxMDExMjAyNFoXDTIxMDUxMDExMjAyNFowcjELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTEfMB0GA1UEAxQWMDUxQGFhYWFhQFpIMDkzNTgwMjhAMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJx3F2WD1dJPzK/nRHO7d1TJ1hTjzGTmv0PQ7ECsJAh3U3BtnGTpCB+b4+JMI4LO8nHkKIBQ3P9XnF+Bf1iXdWNAQ4aWCxa2nV7lCp4w0GliPu/EMgIfmsSDUtgqbM3cr8sR8r9m1xG3gt2TIQJ+jT7sAiguU/kyNzpjaccOUIgUFa8IDFq9UeB76MXtCuhlERRZQCl47e+9w7ZoxmE7e6IZORxPp7rQWVBHlR9ntWjJfNDTm3gMP5ehP+yIZnKx1LudxkBLQxpMmspzOyH1zqx5nkKe49AfWWpDxxRvYkriyYC3aE81qLsU/bhLwNEKOju7BGDF/mhJLZUedojM0gMCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GCGCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjU2OTMuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU5oKGaQs7Jt5Gfbt1XhFTWAySEKswHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAlmPRaImZV51iKjtpMKuyLMw7dX8L0lY3tl+pVZZSxHuwsN4GCCtV0Ej50up+/6EbfL4NUTiuHVAjCroKKvb+94CrdEwdnQGM5IbGSjT78nQpeASXbIWuUwA+ImjvZOzvq/0b56AzonNzBxOMGko/bj5smM6X8jrgJ0NQppo2KNSVNC4JbuoNWI4FM94SE4DUi9H7EYl4JdOtDaDtCsq49o/A1CZyYrmoOPCgxpQQXmuB3lGq/jyoOlW2aW8uee/hYG1JJcSHLBjF0WBwdxssgbBotA5f1PebiIMSbFgjk57bd4M80hhU/rI4Hkn9pcp5R7NsX95TtyDIg90LboBnW"; | String userCert = "MIIEQDCCAyigAwIBAgIFICdVYzEwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxMDExMjAyNFoXDTIxMDUxMDExMjAyNFowcjELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTEfMB0GA1UEAxQWMDUxQGFhYWFhQFpIMDkzNTgwMjhAMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJx3F2WD1dJPzK/nRHO7d1TJ1hTjzGTmv0PQ7ECsJAh3U3BtnGTpCB+b4+JMI4LO8nHkKIBQ3P9XnF+Bf1iXdWNAQ4aWCxa2nV7lCp4w0GliPu/EMgIfmsSDUtgqbM3cr8sR8r9m1xG3gt2TIQJ+jT7sAiguU/kyNzpjaccOUIgUFa8IDFq9UeB76MXtCuhlERRZQCl47e+9w7ZoxmE7e6IZORxPp7rQWVBHlR9ntWjJfNDTm3gMP5ehP+yIZnKx1LudxkBLQxpMmspzOyH1zqx5nkKe49AfWWpDxxRvYkriyYC3aE81qLsU/bhLwNEKOju7BGDF/mhJLZUedojM0gMCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GCGCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjU2OTMuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU5oKGaQs7Jt5Gfbt1XhFTWAySEKswHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAlmPRaImZV51iKjtpMKuyLMw7dX8L0lY3tl+pVZZSxHuwsN4GCCtV0Ej50up+/6EbfL4NUTiuHVAjCroKKvb+94CrdEwdnQGM5IbGSjT78nQpeASXbIWuUwA+ImjvZOzvq/0b56AzonNzBxOMGko/bj5smM6X8jrgJ0NQppo2KNSVNC4JbuoNWI4FM94SE4DUi9H7EYl4JdOtDaDtCsq49o/A1CZyYrmoOPCgxpQQXmuB3lGq/jyoOlW2aW8uee/hYG1JJcSHLBjF0WBwdxssgbBotA5f1PebiIMSbFgjk57bd4M80hhU/rI4Hkn9pcp5R7NsX95TtyDIg90LboBnW"; | ||||
parser.parse(userCert, issuerCert); | parser.parse(userCert, issuerCert); | ||||
assertEquals("SHA1WITHRSA",parser.getSigAlgName()); | |||||
assertEquals("SHA1WITHRSA", parser.getSigAlgName()); | |||||
assertEquals(2048, parser.getKeyLength()); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -77,7 +78,8 @@ public class CertParserTest { | |||||
String userCert = "MIIFRjCCBC6gAwIBAgIFICdWiDMwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxNjA3MDcyMloXDTIxMDUxNjA3MDcyMloweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL0rTOxd8rsjPtFJ0aGVh9bZPy5Xo0SADaP7BbJsG4+ykLQMZHg9hTf/6fv1OsD2HEKFoMpIkW2gwCJW2nvicHcVql/shCoktc6ZBW6Dr/DxOgbO9tpoGxZ50xdI4Q0NsrxqtbCldW4ozPHdjgRJ83i1KSFh7evNrVByN/mB+jchrVGLWyJ1uIRgUUgpRZmZPoOHaizVJqrqWJGGk6xbDLR2gUQ1hTzetQaz1OeKtelHDk9FY08XSmNGssSMpuSjrxn78S888VW5WIxyo4cwrXSXFk3J7LNTy70Oga16HZjJD/vLTM6a4riPa8+uivPinKxK38/++nlBPNwhx6n46uYkd9Zvw+SJiJgpnuPJLtMZpKpJx7V1BDVEydKPUthilTdsmJtkBFSlFw0G1aKfuciBGzzJ3SKngJF/JqJAWIonVAFBGb6Gokp1Sw+T4KqXrdbjxYxiyyjZ++8O1vydgFAkx/NjsuwJnpKETiRKFJmY7YawcUvC4ixF7XQc0luFWRDYcbxOppir+ieMqhGXyaFhLUuB4WXv+rFxfa3NmkBW8q5TPzt/PwWcXpITsYTZYla/E/grB+OeZLYgjigT5YlgytPHG6Gt1ySCCd8WXFWpkBbQfXzqcvtU27RCcAUgfXk5NLb7NZCQg7heGjgzOdYJCPsa1d3m7l04+VIKGCZdAgMBAAGjgfUwgfIwHwYDVR0jBBgwFoAU/Au8RJoOMaGDqYGHJx4FQsa/VvgwSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvUlNBL2NybDI1NzE3LmNybDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFMjh6AzDCuNkD+pqQfiS6bqPGpI4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEApZaLXS6/6FudPA3l2xom5U7nJUOpQ1E6DO/ic9dFGtLE0WgyAqB3JVPvXEntppX55x/dAV7rvvz9NaEdiAe8DAj7qyoPDvC8ZWQK8U4n9l8N78QwALOURxzQNs+CBatJQzbu2w1RKVwkfE6xEIVnu+wjiAtymfwdLHMagHxDIC/eOPbTnbbtITJk2ukFfoc0WJ6Awg5lW+x7nGokEn/XAjKyRHCpkRUFGQm4ww41zlrqCqQqnVGVABJtjbdtFf7nh33QHl0fkj19nfMox9eGuntPyM0bNA0XqPMA+FWSCqeDT6uLbyaOKWxlhv53U/NCJl76U3tssMEWsm9amEDDQg=="; | String userCert = "MIIFRjCCBC6gAwIBAgIFICdWiDMwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxNjA3MDcyMloXDTIxMDUxNjA3MDcyMloweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL0rTOxd8rsjPtFJ0aGVh9bZPy5Xo0SADaP7BbJsG4+ykLQMZHg9hTf/6fv1OsD2HEKFoMpIkW2gwCJW2nvicHcVql/shCoktc6ZBW6Dr/DxOgbO9tpoGxZ50xdI4Q0NsrxqtbCldW4ozPHdjgRJ83i1KSFh7evNrVByN/mB+jchrVGLWyJ1uIRgUUgpRZmZPoOHaizVJqrqWJGGk6xbDLR2gUQ1hTzetQaz1OeKtelHDk9FY08XSmNGssSMpuSjrxn78S888VW5WIxyo4cwrXSXFk3J7LNTy70Oga16HZjJD/vLTM6a4riPa8+uivPinKxK38/++nlBPNwhx6n46uYkd9Zvw+SJiJgpnuPJLtMZpKpJx7V1BDVEydKPUthilTdsmJtkBFSlFw0G1aKfuciBGzzJ3SKngJF/JqJAWIonVAFBGb6Gokp1Sw+T4KqXrdbjxYxiyyjZ++8O1vydgFAkx/NjsuwJnpKETiRKFJmY7YawcUvC4ixF7XQc0luFWRDYcbxOppir+ieMqhGXyaFhLUuB4WXv+rFxfa3NmkBW8q5TPzt/PwWcXpITsYTZYla/E/grB+OeZLYgjigT5YlgytPHG6Gt1ySCCd8WXFWpkBbQfXzqcvtU27RCcAUgfXk5NLb7NZCQg7heGjgzOdYJCPsa1d3m7l04+VIKGCZdAgMBAAGjgfUwgfIwHwYDVR0jBBgwFoAU/Au8RJoOMaGDqYGHJx4FQsa/VvgwSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvUlNBL2NybDI1NzE3LmNybDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFMjh6AzDCuNkD+pqQfiS6bqPGpI4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEApZaLXS6/6FudPA3l2xom5U7nJUOpQ1E6DO/ic9dFGtLE0WgyAqB3JVPvXEntppX55x/dAV7rvvz9NaEdiAe8DAj7qyoPDvC8ZWQK8U4n9l8N78QwALOURxzQNs+CBatJQzbu2w1RKVwkfE6xEIVnu+wjiAtymfwdLHMagHxDIC/eOPbTnbbtITJk2ukFfoc0WJ6Awg5lW+x7nGokEn/XAjKyRHCpkRUFGQm4ww41zlrqCqQqnVGVABJtjbdtFf7nh33QHl0fkj19nfMox9eGuntPyM0bNA0XqPMA+FWSCqeDT6uLbyaOKWxlhv53U/NCJl76U3tssMEWsm9amEDDQg=="; | ||||
parser.parse(userCert, issuerCert); | parser.parse(userCert, issuerCert); | ||||
assertEquals("SHA1WITHRSA",parser.getSigAlgName()); | |||||
assertEquals("SHA1WITHRSA", parser.getSigAlgName()); | |||||
assertEquals(4096, parser.getKeyLength()); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -103,7 +105,8 @@ public class CertParserTest { | |||||
String userCert = "MIICwDCCAmWgAwIBAgIFICdWkWgwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTExMB4XDTE5MDUxNjA4MTA1MVoXDTIxMDUxNjA4MTA1MVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABPvNXpdZ4/4g+wx5qKS94CPkMqpEDhlnXYYW7ZzsbNI4d28sVBz5Ji6dTT1Zx627Kvw4tdUaUt7BVMvZsu3BFlyjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8wSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDIxMDkuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUxR5C/VjASus5zrAAFS4ulMpRjKgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBHM9VAYN1BQADRwAwRAIgVBzVi/fgkknr+2BH2wXeGMXC+Pa6p7rbldUsYMOYoyUCIAmQ4KEk2U1xJZSBpOPy5jN9kmRb+0YH6x04O/2tqCgq"; | String userCert = "MIICwDCCAmWgAwIBAgIFICdWkWgwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTExMB4XDTE5MDUxNjA4MTA1MVoXDTIxMDUxNjA4MTA1MVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABPvNXpdZ4/4g+wx5qKS94CPkMqpEDhlnXYYW7ZzsbNI4d28sVBz5Ji6dTT1Zx627Kvw4tdUaUt7BVMvZsu3BFlyjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8wSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDIxMDkuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUxR5C/VjASus5zrAAFS4ulMpRjKgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBHM9VAYN1BQADRwAwRAIgVBzVi/fgkknr+2BH2wXeGMXC+Pa6p7rbldUsYMOYoyUCIAmQ4KEk2U1xJZSBpOPy5jN9kmRb+0YH6x04O/2tqCgq"; | ||||
parser.parse(userCert, issuerCert); | parser.parse(userCert, issuerCert); | ||||
assertEquals("SM3WITHSM2",parser.getSigAlgName()); | |||||
assertEquals("SM3WITHSM2", parser.getSigAlgName()); | |||||
assertEquals(256, parser.getKeyLength()); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -141,6 +144,7 @@ public class CertParserTest { | |||||
"PrIDl+E4aL3FypntFXHG3T+Keg==\n" + | "PrIDl+E4aL3FypntFXHG3T+Keg==\n" + | ||||
"-----END CERTIFICATE-----"; | "-----END CERTIFICATE-----"; | ||||
parser.parse(issuerCert, CACert); | parser.parse(issuerCert, CACert); | ||||
assertEquals("SM3WITHSM2",parser.getSigAlgName()); | |||||
assertEquals("SM3WITHSM2", parser.getSigAlgName()); | |||||
assertEquals(256, parser.getKeyLength()); | |||||
} | } | ||||
} | } |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>crypto</artifactId> | <artifactId>crypto</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>crypto-sm</artifactId> | <artifactId>crypto-sm</artifactId> | ||||
@@ -13,6 +13,8 @@ import org.bouncycastle.crypto.engines.SM2Engine; | |||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | ||||
import org.bouncycastle.crypto.params.*; | import org.bouncycastle.crypto.params.*; | ||||
import org.bouncycastle.crypto.signers.SM2Signer; | import org.bouncycastle.crypto.signers.SM2Signer; | ||||
import org.bouncycastle.jce.ECNamedCurveTable; | |||||
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; | |||||
import org.bouncycastle.math.ec.*; | import org.bouncycastle.math.ec.*; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
@@ -29,19 +31,10 @@ public class SM2Utils { | |||||
// The length of sm3 output is 32 bytes | // The length of sm3 output is 32 bytes | ||||
private static final int SM3DIGEST_LENGTH = 32; | private static final int SM3DIGEST_LENGTH = 32; | ||||
private static final BigInteger SM2_P = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16); | |||||
private static final BigInteger SM2_A = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16); | |||||
private static final BigInteger SM2_B = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16); | |||||
private static final BigInteger SM2_N = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16); | |||||
private static final BigInteger SM2_H = ECConstants.ONE; | |||||
private static final BigInteger SM2_GX = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16); | |||||
private static final BigInteger SM2_GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16); | |||||
// To get the curve from the equation y^2=x^3+ax+b according the coefficient a and b, | |||||
// with the big prime p, the order n, the cofactor h, and obtain the generator g and the domain's parameters | |||||
private static final ECCurve CURVE = new ECCurve.Fp(SM2_P, SM2_A, SM2_B, SM2_N, SM2_H); | |||||
private static final ECPoint G = CURVE.createPoint(SM2_GX, SM2_GY); | |||||
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G, SM2_N); | |||||
private static final ECNamedCurveParameterSpec PARAMS = ECNamedCurveTable.getParameterSpec("sm2p256v1"); | |||||
private static final ECCurve CURVE = PARAMS.getCurve(); | |||||
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters( | |||||
CURVE, PARAMS.getG(), PARAMS.getN(), PARAMS.getH()); | |||||
//-----------------Key Generation Algorithm----------------- | //-----------------Key Generation Algorithm----------------- | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>jdchain-root</artifactId> | <artifactId>jdchain-root</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>crypto</artifactId> | <artifactId>crypto</artifactId> | ||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
@@ -0,0 +1,20 @@ | |||||
package com.jd.blockchain; | |||||
import static org.junit.Assert.assertTrue; | |||||
import org.junit.Test; | |||||
/** | |||||
* Unit test for simple App. | |||||
*/ | |||||
public class AppTest | |||||
{ | |||||
/** | |||||
* Rigorous Test :-) | |||||
*/ | |||||
@Test | |||||
public void shouldAnswerWithTrue() | |||||
{ | |||||
assertTrue( true ); | |||||
} | |||||
} |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>deployment</artifactId> | <artifactId>deployment</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>deployment-gateway</artifactId> | <artifactId>deployment-gateway</artifactId> | ||||
@@ -18,15 +18,13 @@ public class GatewayBooter { | |||||
writePID(); | writePID(); | ||||
GatewayServerBooter.main(args); | GatewayServerBooter.main(args); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
e.printStackTrace(); | |||||
System.err.println("Error!!! --[" + e.getClass().getName() + "] " + e.getMessage()); | System.err.println("Error!!! --[" + e.getClass().getName() + "] " + e.getMessage()); | ||||
} | } | ||||
} | } | ||||
private static final void writePID() throws Exception { | private static final void writePID() throws Exception { | ||||
URL url = GatewayBooter.class | |||||
.getProtectionDomain() | |||||
.getCodeSource() | |||||
.getLocation(); | |||||
URL url = GatewayBooter.class.getProtectionDomain().getCodeSource().getLocation(); | |||||
String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); | String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); | ||||
if (currPath.contains("!/")) { | if (currPath.contains("!/")) { | ||||
currPath = currPath.substring(5, currPath.indexOf("!/")); | currPath = currPath.substring(5, currPath.indexOf("!/")); | ||||
@@ -40,6 +38,10 @@ public class GatewayBooter { | |||||
String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log"; | String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log"; | ||||
File pidFile = new File(pidFilePath); | File pidFile = new File(pidFilePath); | ||||
if (!pidFile.exists()) { | if (!pidFile.exists()) { | ||||
File dir = pidFile.getParentFile(); | |||||
if (!dir.exists()) { | |||||
dir.mkdirs(); | |||||
} | |||||
pidFile.createNewFile(); | pidFile.createNewFile(); | ||||
} | } | ||||
String name = ManagementFactory.getRuntimeMXBean().getName(); | String name = ManagementFactory.getRuntimeMXBean().getName(); | ||||
@@ -5,5 +5,5 @@ GATEWAY=$(ls $HOME/lib | grep deployment-gateway-) | |||||
if [ ! -n "$GATEWAY" ]; then | if [ ! -n "$GATEWAY" ]; then | ||||
echo "GateWay Is Null !!!" | echo "GateWay Is Null !!!" | ||||
else | else | ||||
nohup java -jar -server $HOME/lib/$GATEWAY -c $HOME/config/gateway.conf $* > gw.out 2>&1 & | |||||
nohup java -jar -server -Dgateway.log=$HOME $HOME/lib/$GATEWAY -c $HOME/config/gateway.conf $* >$HOME/bin/gw.out 2>&1 & | |||||
fi | fi |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>deployment</artifactId> | <artifactId>deployment</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>deployment-peer</artifactId> | <artifactId>deployment-peer</artifactId> | ||||
@@ -25,7 +25,11 @@ | |||||
<artifactId>runtime-modular-booter</artifactId> | <artifactId>runtime-modular-booter</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<!--<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>ump-booter</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency>--> | |||||
<dependency> | <dependency> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>storage-composite</artifactId> | <artifactId>storage-composite</artifactId> | ||||
@@ -55,6 +55,16 @@ | |||||
<exclude>com.jd.blockchain:deployment-peer</exclude> | <exclude>com.jd.blockchain:deployment-peer</exclude> | ||||
</excludes> | </excludes> | ||||
</dependencySet> | </dependencySet> | ||||
<!--<dependencySet> | |||||
<unpack>false</unpack> | |||||
<useProjectArtifact>true</useProjectArtifact> | |||||
<outputDirectory>ext</outputDirectory> | |||||
<includes> | |||||
<include>com.jd.blockchain:ump-booter</include> | |||||
</includes> | |||||
</dependencySet>--> | |||||
</dependencySets> | </dependencySets> | ||||
<moduleSets> | <moduleSets> | ||||
@@ -78,7 +78,7 @@ Peer打包程序解压完后的安装包结构如下: | |||||
其中目录说明如下: | 其中目录说明如下: | ||||
+ **bin** :相关命令操作目录; | + **bin** :相关命令操作目录; | ||||
+ **config** :对应命令的配置目录,keys路径默认可能不存在,会在执行相关脚本时自动创建; | |||||
+ **config** :对应命令的配置目录,keys路径解压时不存在,会在执行keygen.sh脚本时自动创建;ledger-binding.conf文件解压时不存在,会在成功执行ledger-init.sh脚本后生成; | |||||
+ **docs** :相关文档保存目录; | + **docs** :相关文档保存目录; | ||||
+ **libs** :项目运行依赖第三方及非system依赖包保存路径; | + **libs** :项目运行依赖第三方及非system依赖包保存路径; | ||||
+ **system** :项目运行系统包保存路径; | + **system** :项目运行系统包保存路径; | ||||
@@ -0,0 +1,9 @@ | |||||
#!/bin/bash | |||||
HOME=$(cd `dirname $0`;cd ../; pwd) | |||||
UMP=$(ls $HOME/ext | grep ump-booter-) | |||||
if [ ! -n "UMP" ]; then | |||||
echo "Unified Management Platform Is Null !!!" | |||||
else | |||||
nohup java -jar -server -Djump.log=$HOME $HOME/ext/$UMP -p 8000 $* >$HOME/bin/jump.out 2>&1 & | |||||
fi |
@@ -0,0 +1,16 @@ | |||||
#!/bin/bash | |||||
#启动Home路径 | |||||
BOOT_HOME=$(cd `dirname $0`;cd ../; pwd) | |||||
#获取进程PID | |||||
PID=`ps -ef | grep $BOOT_HOME/ext/ump-booter | grep -v grep | awk '{print $2}'` | |||||
#通过Kill命令将进程杀死 | |||||
if [ -z "$PID" ]; then | |||||
echo "Unable to find UMP PID. stop aborted." | |||||
else | |||||
echo "Start to kill PID = $PID ..." | |||||
kill -9 $PID | |||||
echo "Unified Management Platform has been stopped ..." | |||||
fi |
@@ -1,9 +1,9 @@ | |||||
#!/bin/bash | #!/bin/bash | ||||
HOME=$(cd `dirname $0`;cd ../; pwd) | HOME=$(cd `dirname $0`;cd ../; pwd) | ||||
boot_file=$(ls ../libs | grep tools-initializer-booter-) | |||||
boot_file=$(ls $HOME/libs | grep tools-initializer-booter-) | |||||
if [ ! -n "$boot_file" ]; then | if [ ! -n "$boot_file" ]; then | ||||
echo "tools-initializer-booter is null" | echo "tools-initializer-booter is null" | ||||
else | else | ||||
java -jar $HOME/libs/$boot_file -l $HOME/config/init/local.conf -i $HOME/config/init/ledger.init $* | |||||
fi | |||||
java -jar -server -Dinit.log=$HOME $HOME/libs/$boot_file -l $HOME/config/init/local.conf -i $HOME/config/init/ledger.init $* | |||||
fi |
@@ -5,5 +5,5 @@ PEER=$(ls $HOME/system | grep deployment-peer-) | |||||
if [ ! -n "$PEER" ]; then | if [ ! -n "$PEER" ]; then | ||||
echo "Peer Is Null !!!" | echo "Peer Is Null !!!" | ||||
else | else | ||||
nohup java -jar -server -Xmx2g -Xms2g $HOME/system/$PEER -home=$HOME -c $HOME/config/ledger-binding.conf -p 7080 $* & | |||||
nohup java -jar -server -Xmx2g -Xms2g -Dpeer.log=$HOME $HOME/system/$PEER -home=$HOME -c $HOME/config/ledger-binding.conf -p 7080 $* >$HOME/bin/peer.out 2>&1 & | |||||
fi | fi |
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>jdchain-root</artifactId> | <artifactId>jdchain-root</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>deployment</artifactId> | <artifactId>deployment</artifactId> | ||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>jdchain-root</artifactId> | <artifactId>jdchain-root</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>gateway</artifactId> | <artifactId>gateway</artifactId> | ||||
@@ -75,7 +75,6 @@ | |||||
<dependency> | <dependency> | ||||
<groupId>commons-io</groupId> | <groupId>commons-io</groupId> | ||||
<artifactId>commons-io</artifactId> | <artifactId>commons-io</artifactId> | ||||
<version>${commons-io.version}</version> | |||||
</dependency> | </dependency> | ||||
@@ -83,18 +82,13 @@ | |||||
<dependency> | <dependency> | ||||
<groupId>org.springframework.boot</groupId> | <groupId>org.springframework.boot</groupId> | ||||
<artifactId>spring-boot-starter-web</artifactId> | <artifactId>spring-boot-starter-web</artifactId> | ||||
<exclusions> | |||||
<exclusion> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter-logging</artifactId> | |||||
</exclusion> | |||||
</exclusions> | |||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<!-- <dependency> | |||||
<groupId>org.springframework.boot</groupId> | <groupId>org.springframework.boot</groupId> | ||||
<artifactId>spring-boot-starter-log4j2</artifactId> | <artifactId>spring-boot-starter-log4j2</artifactId> | ||||
</dependency> | |||||
</dependency> --> | |||||
<dependency> | <dependency> | ||||
<groupId>org.springframework.boot</groupId> | <groupId>org.springframework.boot</groupId> | ||||
@@ -5,20 +5,20 @@ import java.io.InputStream; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import com.jd.blockchain.gateway.web.BlockBrowserController; | |||||
import org.apache.commons.io.FileUtils; | import org.apache.commons.io.FileUtils; | ||||
import org.springframework.boot.SpringApplication; | import org.springframework.boot.SpringApplication; | ||||
import org.springframework.context.ConfigurableApplicationContext; | import org.springframework.context.ConfigurableApplicationContext; | ||||
import org.springframework.core.io.ClassPathResource; | import org.springframework.core.io.ClassPathResource; | ||||
import com.jd.blockchain.crypto.AsymmetricKeypair; | import com.jd.blockchain.crypto.AsymmetricKeypair; | ||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PrivKey; | import com.jd.blockchain.crypto.PrivKey; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
import com.jd.blockchain.gateway.web.BlockBrowserController; | |||||
import com.jd.blockchain.utils.ArgumentSet; | import com.jd.blockchain.utils.ArgumentSet; | ||||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||||
import com.jd.blockchain.utils.BaseConstant; | import com.jd.blockchain.utils.BaseConstant; | ||||
import com.jd.blockchain.utils.ConsoleUtils; | import com.jd.blockchain.utils.ConsoleUtils; | ||||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||||
public class GatewayServerBooter { | public class GatewayServerBooter { | ||||
@@ -88,19 +88,19 @@ public class GatewayServerBooter { | |||||
String base58Pwd = config.keys().getDefault().getPrivKeyPassword(); | String base58Pwd = config.keys().getDefault().getPrivKeyPassword(); | ||||
if (base58Pwd == null || base58Pwd.length() == 0) { | if (base58Pwd == null || base58Pwd.length() == 0) { | ||||
base58Pwd = KeyGenCommand.readPasswordString(); | |||||
base58Pwd = KeyGenUtils.readPasswordString(); | |||||
} | } | ||||
// 加载密钥; | // 加载密钥; | ||||
PubKey pubKey = KeyGenCommand.decodePubKey(config.keys().getDefault().getPubKeyValue()); | |||||
PubKey pubKey = KeyGenUtils.decodePubKey(config.keys().getDefault().getPubKeyValue()); | |||||
PrivKey privKey = null; | PrivKey privKey = null; | ||||
String base58PrivKey = config.keys().getDefault().getPrivKeyValue(); | String base58PrivKey = config.keys().getDefault().getPrivKeyValue(); | ||||
if (base58PrivKey == null) { | if (base58PrivKey == null) { | ||||
//注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一; | //注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一; | ||||
privKey = KeyGenCommand.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||||
privKey = KeyGenUtils.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||||
} else { | } else { | ||||
privKey = KeyGenCommand.decodePrivKey(base58PrivKey, base58Pwd); | |||||
privKey = KeyGenUtils.decodePrivKey(base58PrivKey, base58Pwd); | |||||
} | } | ||||
defaultKeyPair = new AsymmetricKeypair(pubKey, privKey); | defaultKeyPair = new AsymmetricKeypair(pubKey, privKey); | ||||
} | } | ||||
@@ -4,7 +4,6 @@ import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.sdk.ContractSettings; | import com.jd.blockchain.sdk.ContractSettings; | ||||
import com.jd.blockchain.sdk.LedgerInitSettings; | import com.jd.blockchain.sdk.LedgerInitSettings; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
/** | /** | ||||
* queryService only for gateway; | * queryService only for gateway; | ||||
@@ -6,6 +6,7 @@ import com.jd.blockchain.consensus.ConsensusSettings; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.gateway.PeerService; | import com.jd.blockchain.gateway.PeerService; | ||||
import com.jd.blockchain.ledger.ContractInfo; | import com.jd.blockchain.ledger.ContractInfo; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.LedgerMetadata; | import com.jd.blockchain.ledger.LedgerMetadata; | ||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.sdk.ContractSettings; | import com.jd.blockchain.sdk.ContractSettings; | ||||
@@ -51,7 +52,9 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||||
LedgerMetadata ledgerMetadata = peerService.getQueryService().getLedgerMetadata(ledgerHash); | LedgerMetadata ledgerMetadata = peerService.getQueryService().getLedgerMetadata(ledgerHash); | ||||
return initLedgerInitSettings(participantNodes, ledgerMetadata); | |||||
LedgerAdminInfo ledgerAdminInfo = peerService.getQueryService().getLedgerAdminInfo(ledgerHash); | |||||
return initLedgerInitSettings(participantNodes, ledgerMetadata, ledgerAdminInfo); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -78,26 +81,26 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||||
* 账本元数据 | * 账本元数据 | ||||
* @return | * @return | ||||
*/ | */ | ||||
private LedgerInitSettings initLedgerInitSettings(ParticipantNode[] participantNodes, LedgerMetadata ledgerMetadata) { | |||||
private LedgerInitSettings initLedgerInitSettings(ParticipantNode[] participantNodes, LedgerMetadata ledgerMetadata, LedgerAdminInfo ledgerAdminInfo) { | |||||
LedgerInitSettings ledgerInitSettings = new LedgerInitSettings(); | LedgerInitSettings ledgerInitSettings = new LedgerInitSettings(); | ||||
// 设置参与方 | // 设置参与方 | ||||
ledgerInitSettings.setParticipantNodes(participantNodes); | ledgerInitSettings.setParticipantNodes(participantNodes); | ||||
// 设置共识设置 | // 设置共识设置 | ||||
ledgerInitSettings.setConsensusSettings(initConsensusSettings(ledgerMetadata)); | |||||
ledgerInitSettings.setConsensusSettings(initConsensusSettings(ledgerAdminInfo)); | |||||
// 设置参与方根Hash | // 设置参与方根Hash | ||||
ledgerInitSettings.setParticipantsHash(ledgerMetadata.getParticipantsHash()); | ledgerInitSettings.setParticipantsHash(ledgerMetadata.getParticipantsHash()); | ||||
// 设置算法配置 | // 设置算法配置 | ||||
ledgerInitSettings.setCryptoSetting(ledgerMetadata.getSetting().getCryptoSetting()); | |||||
ledgerInitSettings.setCryptoSetting(ledgerAdminInfo.getSettings().getCryptoSetting()); | |||||
// 设置种子 | // 设置种子 | ||||
ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed())); | ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed())); | ||||
// 设置共识协议 | // 设置共识协议 | ||||
ledgerInitSettings.setConsensusProtocol(ledgerMetadata.getSetting().getConsensusProvider()); | |||||
ledgerInitSettings.setConsensusProtocol(ledgerAdminInfo.getSettings().getConsensusProvider()); | |||||
return ledgerInitSettings; | return ledgerInitSettings; | ||||
} | } | ||||
@@ -129,14 +132,14 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||||
/** | /** | ||||
* 初始化共识配置 | * 初始化共识配置 | ||||
* | * | ||||
* @param ledgerMetadata | |||||
* @param ledgerAdminInfo | |||||
* 账本元数据 | * 账本元数据 | ||||
* @return | * @return | ||||
*/ | */ | ||||
private ConsensusSettings initConsensusSettings(LedgerMetadata ledgerMetadata) { | |||||
String consensusProvider = ledgerMetadata.getSetting().getConsensusProvider(); | |||||
private ConsensusSettings initConsensusSettings(LedgerAdminInfo ledgerAdminInfo) { | |||||
String consensusProvider = ledgerAdminInfo.getSettings().getConsensusProvider(); | |||||
ConsensusProvider provider = ConsensusProviders.getProvider(consensusProvider); | ConsensusProvider provider = ConsensusProviders.getProvider(consensusProvider); | ||||
byte[] consensusSettingsBytes = ledgerMetadata.getSetting().getConsensusSetting().toBytes(); | |||||
byte[] consensusSettingsBytes = ledgerAdminInfo.getSettings().getConsensusSetting().toBytes(); | |||||
return provider.getSettingsFactory().getConsensusSettingsEncoder().decode(consensusSettingsBytes); | return provider.getSettingsFactory().getConsensusSettingsEncoder().decode(consensusSettingsBytes); | ||||
} | } | ||||
} | } |
@@ -35,6 +35,7 @@ public class GatewayWebServerConfigurer implements WebMvcConfigurer { | |||||
JSONSerializeUtils.disableCircularReferenceDetect(); | JSONSerializeUtils.disableCircularReferenceDetect(); | ||||
JSONSerializeUtils.configStringSerializer(ByteArray.class); | JSONSerializeUtils.configStringSerializer(ByteArray.class); | ||||
DataContractRegistry.register(BftsmartNodeSettings.class); | DataContractRegistry.register(BftsmartNodeSettings.class); | ||||
DataContractRegistry.register(LedgerAdminInfo.class); | |||||
} | } | ||||
@@ -1,6 +1,8 @@ | |||||
package com.jd.blockchain.gateway.web; | package com.jd.blockchain.gateway.web; | ||||
import com.jd.blockchain.crypto.*; | |||||
import com.jd.blockchain.gateway.service.GatewayInterceptService; | import com.jd.blockchain.gateway.service.GatewayInterceptService; | ||||
import com.jd.blockchain.transaction.SignatureUtils; | |||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.web.bind.annotation.RequestBody; | import org.springframework.web.bind.annotation.RequestBody; | ||||
import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||
@@ -9,9 +11,6 @@ import org.springframework.web.bind.annotation.ResponseBody; | |||||
import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.crypto.Crypto; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.SignatureFunction; | |||||
import com.jd.blockchain.gateway.PeerService; | import com.jd.blockchain.gateway.PeerService; | ||||
import com.jd.blockchain.ledger.DigitalSignature; | import com.jd.blockchain.ledger.DigitalSignature; | ||||
import com.jd.blockchain.ledger.TransactionContent; | import com.jd.blockchain.ledger.TransactionContent; | ||||
@@ -60,11 +59,8 @@ public class TxProcessingController implements TransactionService { | |||||
throw new IllegalStateException("Not implemented!"); | throw new IllegalStateException("Not implemented!"); | ||||
} else { | } else { | ||||
// 验证签名; | // 验证签名; | ||||
byte[] content = BinaryProtocol.encode(txRequest.getTransactionContent(), TransactionContent.class); | |||||
for (DigitalSignature sign : partiSigns) { | for (DigitalSignature sign : partiSigns) { | ||||
SignatureFunction signFunc = Crypto | |||||
.getSignatureFunction(sign.getPubKey().getAlgorithm()); | |||||
if (!signFunc.verify(sign.getDigest(), sign.getPubKey(), content)) { | |||||
if (!SignatureUtils.verifySignature(txRequest.getTransactionContent(), sign.getDigest(), sign.getPubKey())) { | |||||
throw new BusinessException("The validation of participant signatures fail!"); | throw new BusinessException("The validation of participant signatures fail!"); | ||||
} | } | ||||
} | } | ||||
@@ -8,17 +8,17 @@ | |||||
<!--这个输出控制台的配置--> | <!--这个输出控制台的配置--> | ||||
<console name="Console" target="SYSTEM_OUT"> | <console name="Console" target="SYSTEM_OUT"> | ||||
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--> | <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--> | ||||
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/> | |||||
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> | |||||
<!--输出日志的格式--> | <!--输出日志的格式--> | ||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | ||||
</console> | </console> | ||||
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用--> | <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用--> | ||||
<File name="log" fileName="../logs/test.log" append="false"> | |||||
<File name="log" fileName="${sys:gateway.log}/logs/gateway.temp.log" append="false"> | |||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | ||||
</File> | </File> | ||||
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--> | <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--> | ||||
<RollingFile name="GatewayRollingInfo" fileName="../logs/gateway.out.info.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/gateway.out.info-%d{yyyy-MM-dd}-%i.log"> | |||||
<RollingFile name="GatewayRollingInfo" fileName="${sys:gateway.log}/logs/gateway.info.log" | |||||
filePattern="${sys:gateway.log}/logs/$${date:yyyy-MM}/gateway.info-%d{yyyy-MM-dd}-%i.log"> | |||||
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--> | <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--> | ||||
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> | <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> | ||||
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | ||||
@@ -27,8 +27,8 @@ | |||||
<SizeBasedTriggeringPolicy size="100 MB"/> | <SizeBasedTriggeringPolicy size="100 MB"/> | ||||
</Policies> | </Policies> | ||||
</RollingFile> | </RollingFile> | ||||
<RollingFile name="GatewayRollingWarn" fileName="../logs/gateway.out.warn.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/gateway.out.warn-%d{yyyy-MM-dd}-%i.log"> | |||||
<RollingFile name="GatewayRollingWarn" fileName="${sys:gateway.log}/logs/gateway.warn.log" | |||||
filePattern="${sys:gateway.log}/logs/$${date:yyyy-MM}/gateway.out.warn-%d{yyyy-MM-dd}-%i.log"> | |||||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> | <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> | ||||
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | ||||
<Policies> | <Policies> | ||||
@@ -38,8 +38,8 @@ | |||||
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 --> | <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 --> | ||||
<DefaultRolloverStrategy max="20"/> | <DefaultRolloverStrategy max="20"/> | ||||
</RollingFile> | </RollingFile> | ||||
<RollingFile name="GatewayRollingError" fileName="../logs/gateway.out.error.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/gateway.out.error-%d{yyyy-MM-dd}-%i.log"> | |||||
<RollingFile name="GatewayRollingError" fileName="${sys:gateway.log}/logs/gateway.error.log" | |||||
filePattern="${sys:gateway.log}/logs/$${date:yyyy-MM}/gateway.error-%d{yyyy-MM-dd}-%i.log"> | |||||
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> | <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> | ||||
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | ||||
<Policies> | <Policies> | ||||
@@ -51,7 +51,7 @@ | |||||
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--> | <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--> | ||||
<loggers> | <loggers> | ||||
<!--过滤掉spring的一些DEBUG信息--> | <!--过滤掉spring的一些DEBUG信息--> | ||||
<logger name="org.springframework" level="INFO"></logger> | |||||
<logger name="org.springframework" level="INFO"/> | |||||
<root level="all"> | <root level="all"> | ||||
<appender-ref ref="Console"/> | <appender-ref ref="Console"/> | ||||
<appender-ref ref="GatewayRollingInfo"/> | <appender-ref ref="GatewayRollingInfo"/> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>ledger</artifactId> | <artifactId>ledger</artifactId> | ||||
<version>1.0.0.RELEASE</version> | |||||
<version>1.1.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>ledger-core</artifactId> | <artifactId>ledger-core</artifactId> | ||||
@@ -68,7 +68,7 @@ | |||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
</dependencies> | |||||
</dependencies> | |||||
<build> | <build> | ||||
<plugins> | <plugins> | ||||
@@ -83,42 +83,32 @@ | |||||
</plugins> | </plugins> | ||||
</build> | </build> | ||||
<!--<build> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-surefire-plugin</artifactId> | |||||
<version>2.5</version> | |||||
<configuration> | |||||
<excludes> | |||||
<exclude>**/TransactionBatchProcessorTest.java</exclude> | |||||
</excludes> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | |||||
</build>--> | |||||
<!--<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> | |||||
<excludes> <exclude>**/TransactionBatchProcessorTest.java</exclude> </excludes> | |||||
</configuration> </plugin> </plugins> </build> --> | |||||
<!--<build>--> | |||||
<!--<plugins>--> | |||||
<!--<plugin>--> | |||||
<!--<groupId>org.apache.maven.plugins</groupId>--> | |||||
<!--<artifactId>maven-compiler-plugin</artifactId>--> | |||||
<!--<version>3.1</version>--> | |||||
<!--<configuration>--> | |||||
<!--<source>1.8</source>--> | |||||
<!--<target>1.8</target>--> | |||||
<!--<encoding>UTF-8</encoding>--> | |||||
<!--<compilerArgs>--> | |||||
<!--<!–<arg>-verbose</arg>–>--> | |||||
<!--<!–<arg>-Xlint:unchecked</arg>–>--> | |||||
<!--<!–<arg>-Xlint:deprecation</arg>–>--> | |||||
<!--<!–<arg>-bootclasspath</arg>–>--> | |||||
<!--<!–<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>–>--> | |||||
<!--<arg>-extdirs</arg>--> | |||||
<!--<arg>${project.basedir}/../contract/contract-libs;$JAVA_HOME/jre/lib/ext</arg>--> | |||||
<!--</compilerArgs>--> | |||||
<!--</configuration>--> | |||||
<!--</plugin>--> | |||||
<!--</plugins>--> | |||||
<!--</build>--> | |||||
<!--<build> --> | |||||
<!--<plugins> --> | |||||
<!--<plugin> --> | |||||
<!--<groupId>org.apache.maven.plugins</groupId> --> | |||||
<!--<artifactId>maven-compiler-plugin</artifactId> --> | |||||
<!--<version>3.1</version> --> | |||||
<!--<configuration> --> | |||||
<!--<source>1.8</source> --> | |||||
<!--<target>1.8</target> --> | |||||
<!--<encoding>UTF-8</encoding> --> | |||||
<!--<compilerArgs> --> | |||||
<!--<!–<arg>-verbose</arg>–> --> | |||||
<!--<!–<arg>-Xlint:unchecked</arg>–> --> | |||||
<!--<!–<arg>-Xlint:deprecation</arg>–> --> | |||||
<!--<!–<arg>-bootclasspath</arg>–> --> | |||||
<!--<!–<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>–> --> | |||||
<!--<arg>-extdirs</arg> --> | |||||
<!--<arg>${project.basedir}/../contract/contract-libs;$JAVA_HOME/jre/lib/ext</arg> --> | |||||
<!--</compilerArgs> --> | |||||
<!--</configuration> --> | |||||
<!--</plugin> --> | |||||
<!--</plugins> --> | |||||
<!--</build> --> | |||||
</project> | </project> |
@@ -1,26 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public interface AccountPrivilege { | |||||
/** | |||||
* 数据“读”的操作码; | |||||
* | |||||
* @return | |||||
*/ | |||||
byte getReadingOpCode(); | |||||
/** | |||||
* “写”的操作码; | |||||
* | |||||
* @return | |||||
*/ | |||||
byte getWrittingOpCode(); | |||||
/** | |||||
* 其它的扩展操作码; | |||||
* | |||||
* @return | |||||
*/ | |||||
byte[] getExtOpCodes(); | |||||
} |
@@ -12,6 +12,7 @@ import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.LedgerException; | import com.jd.blockchain.ledger.LedgerException; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -48,6 +49,10 @@ public class AccountSet implements Transactional, MerkleProvable { | |||||
public boolean isReadonly() { | public boolean isReadonly() { | ||||
return merkleDataset.isReadonly(); | return merkleDataset.isReadonly(); | ||||
} | } | ||||
void setReadonly() { | |||||
merkleDataset.setReadonly(); | |||||
} | |||||
public AccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, | public AccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, | ||||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | ||||
@@ -65,10 +70,6 @@ public class AccountSet implements Transactional, MerkleProvable { | |||||
this.accessPolicy = accessPolicy; | this.accessPolicy = accessPolicy; | ||||
} | } | ||||
// public HashDigest getAccountRootHash() { | |||||
// return merkleDataset.getRootHash(); | |||||
// } | |||||
@Override | @Override | ||||
public HashDigest getRootHash() { | public HashDigest getRootHash() { | ||||
return merkleDataset.getRootHash(); | return merkleDataset.getRootHash(); | ||||
@@ -333,9 +334,9 @@ public class AccountSet implements Transactional, MerkleProvable { | |||||
if (!updated) { | if (!updated) { | ||||
return; | return; | ||||
} | } | ||||
String[] addresses = new String[latestAccountsCache.size()]; | |||||
Bytes[] addresses = new Bytes[latestAccountsCache.size()]; | |||||
latestAccountsCache.keySet().toArray(addresses); | latestAccountsCache.keySet().toArray(addresses); | ||||
for (String address : addresses) { | |||||
for (Bytes address : addresses) { | |||||
VersioningAccount acc = latestAccountsCache.remove(address); | VersioningAccount acc = latestAccountsCache.remove(address); | ||||
// cancel; | // cancel; | ||||
if (acc.isUpdated()) { | if (acc.isUpdated()) { | ||||
@@ -1,168 +0,0 @@ | |||||
//package com.jd.blockchain.ledger.core; | |||||
// | |||||
//import com.jd.blockchain.crypto.hash.HashDigest; | |||||
// | |||||
//import my.utils.Scratchable; | |||||
//import my.utils.io.ByteArray; | |||||
//import my.utils.io.BytesUtils; | |||||
//import my.utils.io.ExistancePolicyKVStorage; | |||||
//import my.utils.io.VersioningKVStorage; | |||||
// | |||||
///** | |||||
// * 可进行授权控制的数据集合; | |||||
// * | |||||
// * @author huanghaiquan | |||||
// * | |||||
// */ | |||||
//public class AuthorizableDataSet implements Scratchable { | |||||
// | |||||
// public static final String DATA_PREFIX = "DATA" + LedgerConsts.KEY_SEPERATOR; | |||||
//// public static final String PRIVILEGE_PREFIX = "PRVL" + LedgerConsts.KEY_SEPERATOR; | |||||
// | |||||
// private static final String DEFAULT_PRIVILEGE_KEY = "%"; | |||||
// | |||||
// private DataAccessable accessable; | |||||
// | |||||
// protected MerkleDataSet data; | |||||
// | |||||
//// private PrivilegeDataSet privileges; | |||||
// | |||||
// /** | |||||
// * Create a new Account instance; | |||||
// * | |||||
// * @param address | |||||
// * @param pubKey | |||||
// */ | |||||
// protected AuthorizableDataSet(CryptoSetting merkleTreeSetting, ExistancePolicyKVStorage simpleStorage, | |||||
// VersioningKVStorage versioningStorage) { | |||||
// this(null, merkleTreeSetting, null, simpleStorage, versioningStorage); | |||||
// } | |||||
// | |||||
// protected AuthorizableDataSet(byte[] dataRootHash, CryptoSetting merkleTreeSetting, byte[] privilegeRootHash, | |||||
// ExistancePolicyKVStorage simpleStorage, VersioningKVStorage versioningStorage) { | |||||
// this(dataRootHash, merkleTreeSetting, privilegeRootHash, simpleStorage, versioningStorage, false); | |||||
// } | |||||
// | |||||
// protected AuthorizableDataSet(byte[] dataRootHash, CryptoSetting merkleTreeSetting, byte[] privilegeRootHash, | |||||
// ExistancePolicyKVStorage simpleStorage, VersioningKVStorage versioningStorage, boolean readonly) { | |||||
// this.data = new MerkleDataSet(dataRootHash, merkleTreeSetting, | |||||
// PrefixAppender.prefix(DATA_PREFIX, simpleStorage), | |||||
// PrefixAppender.prefix(DATA_PREFIX, versioningStorage), readonly); | |||||
// | |||||
//// this.privileges = new PrivilegeDataSet(privilegeRootHash, merkleTreeSetting, | |||||
//// PrefixAppender.prefix(PRIVILEGE_PREFIX, simpleStorage), | |||||
//// PrefixAppender.prefix(PRIVILEGE_PREFIX, versioningStorage), readonly); | |||||
// } | |||||
// | |||||
// public ByteArray getDataRootHash() { | |||||
// return data.getRootHash(); | |||||
// } | |||||
// | |||||
//// public ByteArray getPrivilegeRootHash() { | |||||
//// return privileges.getRootHash(); | |||||
//// } | |||||
// | |||||
// /** | |||||
// * | |||||
// * @param userAddress | |||||
// * @param op | |||||
// * @param enable | |||||
// */ | |||||
// public void setPrivilege(String userAddress, byte op, boolean enable) { | |||||
// | |||||
// } | |||||
// | |||||
// /** | |||||
// * | |||||
// * @param op | |||||
// * @param enable | |||||
// */ | |||||
// public void setDefaultPrivilege(byte op, boolean enable) { | |||||
// } | |||||
// | |||||
// public boolean checkCurrentUserPrivilege() { | |||||
// return false; | |||||
// } | |||||
// | |||||
// /** | |||||
// * Return the latest version entry associated the specified key; If the key | |||||
// * doesn't exist, then return -1; | |||||
// * | |||||
// * @param key | |||||
// * @return | |||||
// */ | |||||
// public long getVersion(String key) { | |||||
// return data.getVersion(key); | |||||
// } | |||||
// | |||||
// protected long setString(String key, String value, long version) { | |||||
// checkWritting(); | |||||
// byte[] bytes = BytesUtils.toBytes(value, LedgerConsts.CHARSET); | |||||
// return data.setValue(key, bytes, version); | |||||
// } | |||||
// | |||||
// protected String getString(String key) { | |||||
// checkReading(); | |||||
// byte[] value = data.getValue(key); | |||||
// return BytesUtils.toString(value, LedgerConsts.CHARSET); | |||||
// } | |||||
// | |||||
// protected String getString(String key, long version) { | |||||
// checkReading(); | |||||
// byte[] value = data.getValue(key, version); | |||||
// return BytesUtils.toString(value, LedgerConsts.CHARSET); | |||||
// } | |||||
// | |||||
// protected long setValue(String key, byte[] value, long version) { | |||||
// checkWritting(); | |||||
// return data.setValue(key, value, version); | |||||
// } | |||||
// | |||||
// protected byte[] getValue(String key) { | |||||
// checkReading(); | |||||
// return data.getValue(key); | |||||
// } | |||||
// | |||||
// protected byte[] getValue(String key, long version) { | |||||
// checkReading(); | |||||
// return data.getValue(key, version); | |||||
// } | |||||
// | |||||
// private void checkWritting() { | |||||
// // Check writting enable; | |||||
// } | |||||
// | |||||
// private void checkReading() { | |||||
// // TODO Check privilege of reading; | |||||
// } | |||||
// | |||||
// // /** | |||||
// // * 数据“读”的操作码; | |||||
// // * | |||||
// // * @return | |||||
// // */ | |||||
// // protected abstract AccountPrivilege getPrivilege(); | |||||
// | |||||
// @Override | |||||
// public boolean isUpdated() { | |||||
// return data.isUpdated(); | |||||
//// return data.isUpdated()|| privileges.isUpdated(); | |||||
// } | |||||
// | |||||
// @Override | |||||
// public void commit() { | |||||
// if (data.isUpdated()) { | |||||
// data.commit(); | |||||
// } | |||||
//// if (privileges.isUpdated()) { | |||||
//// privileges.commit(); | |||||
//// } | |||||
// } | |||||
// | |||||
// @Override | |||||
// public void cancel() { | |||||
// data.cancel(); | |||||
//// privileges.cancel(); | |||||
// } | |||||
// | |||||
//} |
@@ -1,40 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.DigitalSignature; | |||||
/** | |||||
* {@link Authorization} 抽象了对特定用户/角色的授权信息; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public interface Authorization { | |||||
/** | |||||
* 被授权用户/角色的地址; | |||||
* | |||||
* @return | |||||
*/ | |||||
String getAddress(); | |||||
/** | |||||
* 授权码;<br> | |||||
* | |||||
* @return | |||||
*/ | |||||
byte[] getCode(); | |||||
/** | |||||
* 授权者的签名; | |||||
* | |||||
* @return | |||||
*/ | |||||
DigitalSignature getSignature(); | |||||
// /** | |||||
// * 授权生成的时间戳; | |||||
// * @return | |||||
// */ | |||||
// long getTs(); | |||||
} |
@@ -1,42 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.DigitalSignature; | |||||
public class AuthorizationVO implements Authorization { | |||||
private String address; | |||||
private byte[] code; | |||||
private DigitalSignature signature; | |||||
@Override | |||||
public String getAddress() { | |||||
return address; | |||||
} | |||||
public void setAddress(String address) { | |||||
this.address = address; | |||||
} | |||||
@Override | |||||
public byte[] getCode() { | |||||
return code; | |||||
} | |||||
public void setCode(byte[] code) { | |||||
this.code = code; | |||||
} | |||||
@Override | |||||
public DigitalSignature getSignature() { | |||||
return signature; | |||||
} | |||||
public void setSignature(DigitalSignature signature) { | |||||
this.signature = signature; | |||||
} | |||||
} |
@@ -8,6 +8,7 @@ import com.jd.blockchain.ledger.BlockchainIdentity; | |||||
import com.jd.blockchain.ledger.BlockchainIdentityData; | import com.jd.blockchain.ledger.BlockchainIdentityData; | ||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -64,13 +65,13 @@ public class BaseAccount implements AccountHeader, MerkleProvable, Transactional | |||||
/** | /** | ||||
* Create a account instance with the specified address and pubkey and load it's | * Create a account instance with the specified address and pubkey and load it's | ||||
* merkle dataset with the specified root hash. which is used for storing data | |||||
* merkle dataset from the specified root hash. This merkle dateset is used for storing data | |||||
* of this account.<br> | * of this account.<br> | ||||
* | * | ||||
* @param address | * @param address | ||||
* @param pubKey | * @param pubKey | ||||
* @param dataRootHash merkle root hash of account's data; if null be set, | |||||
* create a new empty merkle dataset; | |||||
* @param dataRootHash merkle root hash of account's data; if set to a null value, | |||||
* an empty merkle dataset is created; | |||||
* @param cryptoSetting | * @param cryptoSetting | ||||
* @param exStorage | * @param exStorage | ||||
* @param verStorage | * @param verStorage | ||||
@@ -1,21 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
/** | |||||
* @author hhq | |||||
* @version 1.0 | |||||
* @created 14-6��-2018 12:13:32 | |||||
*/ | |||||
public class Consensus { | |||||
public P2PRealm m_P2PRealm; | |||||
public Consensus(){ | |||||
} | |||||
public void finalize() throws Throwable { | |||||
} | |||||
} |
@@ -2,10 +2,10 @@ package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.BytesData; | import com.jd.blockchain.ledger.BytesData; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.ContractInfo; | import com.jd.blockchain.ledger.ContractInfo; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
public class ContractAccount implements ContractInfo { | public class ContractAccount implements ContractInfo { | ||||
@@ -0,0 +1,29 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public interface ContractAccountQuery { | |||||
AccountHeader[] getAccounts(int fromIndex, int count); | |||||
HashDigest getRootHash(); | |||||
/** | |||||
* 返回合约总数; | |||||
* | |||||
* @return | |||||
*/ | |||||
long getTotalCount(); | |||||
MerkleProof getProof(Bytes address); | |||||
boolean contains(Bytes address); | |||||
ContractAccount getContract(Bytes address); | |||||
ContractAccount getContract(Bytes address, long version); | |||||
} |
@@ -5,12 +5,13 @@ import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.DigitalSignature; | import com.jd.blockchain.ledger.DigitalSignature; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
public class ContractAccountSet implements MerkleProvable, Transactional, ContractAccountQuery { | |||||
private AccountSet accountSet; | private AccountSet accountSet; | ||||
@@ -25,6 +26,7 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | ||||
} | } | ||||
@Override | |||||
public AccountHeader[] getAccounts(int fromIndex, int count) { | public AccountHeader[] getAccounts(int fromIndex, int count) { | ||||
return accountSet.getAccounts(fromIndex,count); | return accountSet.getAccounts(fromIndex,count); | ||||
} | } | ||||
@@ -33,6 +35,10 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
return accountSet.isReadonly(); | return accountSet.isReadonly(); | ||||
} | } | ||||
void setReadonly() { | |||||
accountSet.setReadonly(); | |||||
} | |||||
@Override | @Override | ||||
public HashDigest getRootHash() { | public HashDigest getRootHash() { | ||||
return accountSet.getRootHash(); | return accountSet.getRootHash(); | ||||
@@ -43,6 +49,7 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
* | * | ||||
* @return | * @return | ||||
*/ | */ | ||||
@Override | |||||
public long getTotalCount() { | public long getTotalCount() { | ||||
return accountSet.getTotalCount(); | return accountSet.getTotalCount(); | ||||
} | } | ||||
@@ -52,15 +59,18 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
return accountSet.getProof(address); | return accountSet.getProof(address); | ||||
} | } | ||||
@Override | |||||
public boolean contains(Bytes address) { | public boolean contains(Bytes address) { | ||||
return accountSet.contains(address); | return accountSet.contains(address); | ||||
} | } | ||||
@Override | |||||
public ContractAccount getContract(Bytes address) { | public ContractAccount getContract(Bytes address) { | ||||
BaseAccount accBase = accountSet.getAccount(address); | BaseAccount accBase = accountSet.getAccount(address); | ||||
return new ContractAccount(accBase); | return new ContractAccount(accBase); | ||||
} | } | ||||
@Override | |||||
public ContractAccount getContract(Bytes address, long version) { | public ContractAccount getContract(Bytes address, long version) { | ||||
BaseAccount accBase = accountSet.getAccount(address, version); | BaseAccount accBase = accountSet.getAccount(address, version); | ||||
return new ContractAccount(accBase); | return new ContractAccount(accBase); | ||||
@@ -82,7 +82,7 @@ public class CryptoConfig implements CryptoSetting { | |||||
public void setHashAlgorithm(short hashAlgorithm) { | public void setHashAlgorithm(short hashAlgorithm) { | ||||
if (codeAlgorithms == null || !codeAlgorithms.containsKey(hashAlgorithm)) { | if (codeAlgorithms == null || !codeAlgorithms.containsKey(hashAlgorithm)) { | ||||
throw new LedgerException("The specified algorithm[" + hashAlgorithm + "] has no provider!"); | |||||
throw new LedgerException("Current CryptoConfig has no crypto provider!"); | |||||
} | } | ||||
this.hashAlgorithm = hashAlgorithm; | this.hashAlgorithm = hashAlgorithm; | ||||
} | } | ||||
@@ -1,14 +1,14 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.BytesData; | import com.jd.blockchain.ledger.BytesData; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | import com.jd.blockchain.ledger.KVDataEntry; | ||||
import com.jd.blockchain.ledger.KVDataObject; | import com.jd.blockchain.ledger.KVDataObject; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
public class DataAccount implements AccountHeader, MerkleProvable { | public class DataAccount implements AccountHeader, MerkleProvable { | ||||
@@ -43,16 +43,85 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
} | } | ||||
/** | |||||
* Create or update the value associated the specified key if the version | |||||
* checking is passed.<br> | |||||
* | |||||
* The value of the key will be updated only if it's latest version equals the | |||||
* specified version argument. <br> | |||||
* If the key doesn't exist, the version checking will be ignored, and key will | |||||
* be created with a new sequence number as id. <br> | |||||
* It also could specify the version argument to -1 to ignore the version | |||||
* checking. | |||||
* <p> | |||||
* If updating is performed, the version of the key increase by 1. <br> | |||||
* If creating is performed, the version of the key initialize by 0. <br> | |||||
* | |||||
* @param key The key of data; | |||||
* @param value The value of data; | |||||
* @param version The expected version of the key. | |||||
* @return The new version of the key. <br> | |||||
* If the key is new created success, then return 0; <br> | |||||
* If the key is updated success, then return the new version;<br> | |||||
* If this operation fail by version checking or other reason, then | |||||
* return -1; | |||||
*/ | |||||
public long setBytes(Bytes key, BytesValue value, long version) { | public long setBytes(Bytes key, BytesValue value, long version) { | ||||
return baseAccount.setBytes(key, value, version); | return baseAccount.setBytes(key, value, version); | ||||
} | } | ||||
/** | |||||
* Create or update the value associated the specified key if the version | |||||
* checking is passed.<br> | |||||
* | |||||
* The value of the key will be updated only if it's latest version equals the | |||||
* specified version argument. <br> | |||||
* If the key doesn't exist, the version checking will be ignored, and key will | |||||
* be created with a new sequence number as id. <br> | |||||
* It also could specify the version argument to -1 to ignore the version | |||||
* checking. | |||||
* <p> | |||||
* If updating is performed, the version of the key increase by 1. <br> | |||||
* If creating is performed, the version of the key initialize by 0. <br> | |||||
* | |||||
* @param key The key of data; | |||||
* @param value The value of data; | |||||
* @param version The expected version of the key. | |||||
* @return The new version of the key. <br> | |||||
* If the key is new created success, then return 0; <br> | |||||
* If the key is updated success, then return the new version;<br> | |||||
* If this operation fail by version checking or other reason, then | |||||
* return -1; | |||||
*/ | |||||
public long setBytes(Bytes key, String value, long version) { | public long setBytes(Bytes key, String value, long version) { | ||||
BytesValue bytesValue = BytesData.fromText(value); | BytesValue bytesValue = BytesData.fromText(value); | ||||
return baseAccount.setBytes(key, bytesValue, version); | return baseAccount.setBytes(key, bytesValue, version); | ||||
} | } | ||||
/** | |||||
* Create or update the value associated the specified key if the version | |||||
* checking is passed.<br> | |||||
* | |||||
* The value of the key will be updated only if it's latest version equals the | |||||
* specified version argument. <br> | |||||
* If the key doesn't exist, the version checking will be ignored, and key will | |||||
* be created with a new sequence number as id. <br> | |||||
* It also could specify the version argument to -1 to ignore the version | |||||
* checking. | |||||
* <p> | |||||
* If updating is performed, the version of the key increase by 1. <br> | |||||
* If creating is performed, the version of the key initialize by 0. <br> | |||||
* | |||||
* @param key The key of data; | |||||
* @param value The value of data; | |||||
* @param version The expected version of the key. | |||||
* @return The new version of the key. <br> | |||||
* If the key is new created success, then return 0; <br> | |||||
* If the key is updated success, then return the new version;<br> | |||||
* If this operation fail by version checking or other reason, then | |||||
* return -1; | |||||
*/ | |||||
public long setBytes(Bytes key, byte[] value, long version) { | public long setBytes(Bytes key, byte[] value, long version) { | ||||
BytesValue bytesValue = BytesData.fromBytes(value); | BytesValue bytesValue = BytesData.fromBytes(value); | ||||
return baseAccount.setBytes(key, bytesValue, version); | return baseAccount.setBytes(key, bytesValue, version); | ||||
@@ -121,6 +190,29 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
public BytesValue getBytes(Bytes key, long version) { | public BytesValue getBytes(Bytes key, long version) { | ||||
return baseAccount.getBytes(key, version); | return baseAccount.getBytes(key, version); | ||||
} | } | ||||
/** | |||||
* @param key | |||||
* @param version | |||||
* @return | |||||
*/ | |||||
public KVDataEntry getDataEntry(String key, long version) { | |||||
return getDataEntry(Bytes.fromString(key), version); | |||||
} | |||||
/** | |||||
* @param key | |||||
* @param version | |||||
* @return | |||||
*/ | |||||
public KVDataEntry getDataEntry(Bytes key, long version) { | |||||
BytesValue value = baseAccount.getBytes(key, version); | |||||
if (value == null) { | |||||
return new KVDataObject(key.toUTF8String(), -1, null); | |||||
}else { | |||||
return new KVDataObject(key.toUTF8String(), version, value); | |||||
} | |||||
} | |||||
/** | /** | ||||
* return the specified index's KVDataEntry; | * return the specified index's KVDataEntry; | ||||
@@ -131,7 +223,7 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
*/ | */ | ||||
public KVDataEntry[] getDataEntries(int fromIndex, int count) { | public KVDataEntry[] getDataEntries(int fromIndex, int count) { | ||||
if (getDataEntriesTotalCount() == 0 || count == 0) { | |||||
if (count == 0 || getDataEntriesTotalCount() == 0) { | |||||
return null; | return null; | ||||
} | } | ||||
@@ -0,0 +1,32 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public interface DataAccountQuery { | |||||
AccountHeader[] getAccounts(int fromIndex, int count); | |||||
HashDigest getRootHash(); | |||||
long getTotalCount(); | |||||
/** | |||||
* 返回账户的存在性证明; | |||||
*/ | |||||
MerkleProof getProof(Bytes address); | |||||
/** | |||||
* 返回数据账户; <br> | |||||
* 如果不存在,则返回 null; | |||||
* | |||||
* @param address | |||||
* @return | |||||
*/ | |||||
DataAccount getDataAccount(Bytes address); | |||||
DataAccount getDataAccount(Bytes address, long version); | |||||
} |
@@ -5,18 +5,19 @@ import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.DigitalSignature; | import com.jd.blockchain.ledger.DigitalSignature; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
public class DataAccountSet implements MerkleProvable, Transactional { | |||||
public class DataAccountSet implements MerkleProvable, Transactional, DataAccountQuery { | |||||
private AccountSet accountSet; | private AccountSet accountSet; | ||||
public DataAccountSet(CryptoSetting cryptoSetting, String prefix,ExPolicyKVStorage exStorage, | |||||
public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | |||||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | ||||
accountSet = new AccountSet(cryptoSetting,prefix, exStorage, verStorage, accessPolicy); | |||||
accountSet = new AccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); | |||||
} | } | ||||
public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | ||||
@@ -25,19 +26,25 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||||
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | ||||
} | } | ||||
@Override | |||||
public AccountHeader[] getAccounts(int fromIndex, int count) { | public AccountHeader[] getAccounts(int fromIndex, int count) { | ||||
return accountSet.getAccounts(fromIndex,count); | |||||
return accountSet.getAccounts(fromIndex, count); | |||||
} | } | ||||
public boolean isReadonly() { | public boolean isReadonly() { | ||||
return accountSet.isReadonly(); | return accountSet.isReadonly(); | ||||
} | } | ||||
void setReadonly() { | |||||
accountSet.setReadonly(); | |||||
} | |||||
@Override | @Override | ||||
public HashDigest getRootHash() { | public HashDigest getRootHash() { | ||||
return accountSet.getRootHash(); | return accountSet.getRootHash(); | ||||
} | } | ||||
@Override | |||||
public long getTotalCount() { | public long getTotalCount() { | ||||
return accountSet.getTotalCount(); | return accountSet.getTotalCount(); | ||||
} | } | ||||
@@ -56,11 +63,23 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||||
return new DataAccount(accBase); | return new DataAccount(accBase); | ||||
} | } | ||||
/** | |||||
* 返回数据账户; <br> | |||||
* 如果不存在,则返回 null; | |||||
* | |||||
* @param address | |||||
* @return | |||||
*/ | |||||
@Override | |||||
public DataAccount getDataAccount(Bytes address) { | public DataAccount getDataAccount(Bytes address) { | ||||
BaseAccount accBase = accountSet.getAccount(address); | BaseAccount accBase = accountSet.getAccount(address); | ||||
if (accBase == null) { | |||||
return null; | |||||
} | |||||
return new DataAccount(accBase); | return new DataAccount(accBase); | ||||
} | } | ||||
@Override | |||||
public DataAccount getDataAccount(Bytes address, long version) { | public DataAccount getDataAccount(Bytes address, long version) { | ||||
BaseAccount accBase = accountSet.getAccount(address, version); | BaseAccount accBase = accountSet.getAccount(address, version); | ||||
return new DataAccount(accBase); | return new DataAccount(accBase); | ||||
@@ -0,0 +1,132 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import org.springframework.stereotype.Component; | |||||
import com.jd.blockchain.ledger.LedgerException; | |||||
import com.jd.blockchain.ledger.Operation; | |||||
import com.jd.blockchain.ledger.core.handles.ContractCodeDeployOperationHandle; | |||||
import com.jd.blockchain.ledger.core.handles.DataAccountKVSetOperationHandle; | |||||
import com.jd.blockchain.ledger.core.handles.DataAccountRegisterOperationHandle; | |||||
import com.jd.blockchain.ledger.core.handles.JVMContractEventSendOperationHandle; | |||||
import com.jd.blockchain.ledger.core.handles.LedgerInitOperationHandle; | |||||
import com.jd.blockchain.ledger.core.handles.RolesConfigureOperationHandle; | |||||
import com.jd.blockchain.ledger.core.handles.UserAuthorizeOperationHandle; | |||||
import com.jd.blockchain.ledger.core.handles.UserRegisterOperationHandle; | |||||
import com.jd.blockchain.transaction.ContractCodeDeployOpTemplate; | |||||
import com.jd.blockchain.transaction.ContractEventSendOpTemplate; | |||||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||||
import com.jd.blockchain.transaction.DataAccountRegisterOpTemplate; | |||||
import com.jd.blockchain.transaction.LedgerInitOpTemplate; | |||||
import com.jd.blockchain.transaction.RolesConfigureOpTemplate; | |||||
import com.jd.blockchain.transaction.UserAuthorizeOpTemplate; | |||||
import com.jd.blockchain.transaction.UserRegisterOpTemplate; | |||||
@Component | |||||
public class DefaultOperationHandleRegisteration implements OperationHandleRegisteration { | |||||
private static Map<Class<?>, OperationHandle> DEFAULT_HANDLES = new HashMap<>(); | |||||
private Map<Class<?>, OperationHandle> handles = new ConcurrentHashMap<>(); | |||||
static { | |||||
registerDefaultHandle(new LedgerInitOperationHandle()); | |||||
registerDefaultHandle(new RolesConfigureOperationHandle()); | |||||
registerDefaultHandle(new UserAuthorizeOperationHandle()); | |||||
registerDefaultHandle(new UserRegisterOperationHandle()); | |||||
registerDefaultHandle(new DataAccountKVSetOperationHandle()); | |||||
registerDefaultHandle(new DataAccountRegisterOperationHandle()); | |||||
registerDefaultHandle(new ContractCodeDeployOperationHandle()); | |||||
registerDefaultHandle(new JVMContractEventSendOperationHandle()); | |||||
} | |||||
private static void registerDefaultHandle(OperationHandle handle) { | |||||
DEFAULT_HANDLES.put(handle.getOperationType(), handle); | |||||
} | |||||
/** | |||||
* 注册操作处理器;此方法将覆盖默认的操作处理器配置; | |||||
* | |||||
* @param handle | |||||
*/ | |||||
public void registerHandle(OperationHandle handle) { | |||||
List<Class<?>> opTypes = new ArrayList<Class<?>>(); | |||||
for (Class<?> opType : handles.keySet()) { | |||||
if (opType.isAssignableFrom(handle.getOperationType())) { | |||||
opTypes.add(opType); | |||||
} | |||||
} | |||||
for (Class<?> opType : opTypes) { | |||||
handles.put(opType, handle); | |||||
} | |||||
handles.put(handle.getOperationType(), handle); | |||||
} | |||||
private OperationHandle getRegisteredHandle(Class<?> operationType) { | |||||
OperationHandle hdl = handles.get(operationType); | |||||
if (hdl == null) { | |||||
hdl = DEFAULT_HANDLES.get(operationType); | |||||
//按“操作类型”的继承关系匹配; | |||||
if (hdl == null) { | |||||
for (Class<?> opType : handles.keySet()) { | |||||
if (opType.isAssignableFrom(operationType)) { | |||||
hdl = handles.get(opType); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (hdl == null) { | |||||
for (Class<?> opType : DEFAULT_HANDLES.keySet()) { | |||||
if (opType.isAssignableFrom(operationType)) { | |||||
hdl = DEFAULT_HANDLES.get(opType); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (hdl != null) { | |||||
handles.put(operationType, hdl); | |||||
} | |||||
} | |||||
return hdl; | |||||
} | |||||
/* | |||||
* (non-Javadoc) | |||||
* | |||||
* @see | |||||
* com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration#getHandle( | |||||
* java.lang.Class) | |||||
*/ | |||||
@Override | |||||
public OperationHandle getHandle(Class<? extends Operation> operationType) { | |||||
OperationHandle hdl = getRegisteredHandle(operationType); | |||||
if (hdl == null) { | |||||
throw new LedgerException("Unsupported operation type[" + operationType.getName() + "]!"); | |||||
} | |||||
return hdl; | |||||
} | |||||
private static class OpHandleStub { | |||||
private Class<? extends Operation> operationType; | |||||
private OperationHandle operationHandle; | |||||
} | |||||
} |
@@ -0,0 +1,209 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.ledger.ParticipantDataQuery; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public class EmptyLedgerDataset implements LedgerDataQuery { | |||||
private static final LedgerAdminDataQuery EMPTY_ADMIN_DATA = new EmptyAdminData(); | |||||
private static final UserAccountQuery EMPTY_USER_ACCOUNTS = new EmptyUserAccountSet(); | |||||
private static final DataAccountQuery EMPTY_DATA_ACCOUNTS = new EmptyDataAccountSet(); | |||||
private static final ContractAccountQuery EMPTY_CONTRACT_ACCOUNTS = new EmptyContractAccountSet(); | |||||
private static final ParticipantDataQuery EMPTY_PARTICIPANTS = new EmptyParticipantData(); | |||||
@Override | |||||
public LedgerAdminDataQuery getAdminDataset() { | |||||
return EMPTY_ADMIN_DATA; | |||||
} | |||||
@Override | |||||
public UserAccountQuery getUserAccountSet() { | |||||
return EMPTY_USER_ACCOUNTS; | |||||
} | |||||
@Override | |||||
public DataAccountQuery getDataAccountSet() { | |||||
return EMPTY_DATA_ACCOUNTS; | |||||
} | |||||
@Override | |||||
public ContractAccountQuery getContractAccountset() { | |||||
return EMPTY_CONTRACT_ACCOUNTS; | |||||
} | |||||
private static class EmptyAdminData implements LedgerAdminDataQuery{ | |||||
@Override | |||||
public LedgerAdminInfo getAdminInfo() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public ParticipantDataQuery getParticipantDataset() { | |||||
return EMPTY_PARTICIPANTS; | |||||
} | |||||
} | |||||
private static class EmptyParticipantData implements ParticipantDataQuery{ | |||||
@Override | |||||
public HashDigest getRootHash() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public MerkleProof getProof(Bytes key) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public long getParticipantCount() { | |||||
return 0; | |||||
} | |||||
@Override | |||||
public boolean contains(Bytes address) { | |||||
return false; | |||||
} | |||||
@Override | |||||
public ParticipantNode getParticipant(Bytes address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public ParticipantNode[] getParticipants() { | |||||
return null; | |||||
} | |||||
} | |||||
private static class EmptyUserAccountSet implements UserAccountQuery{ | |||||
@Override | |||||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public long getTotalCount() { | |||||
return 0; | |||||
} | |||||
@Override | |||||
public HashDigest getRootHash() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public MerkleProof getProof(Bytes key) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public UserAccount getUser(String address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public UserAccount getUser(Bytes address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public boolean contains(Bytes address) { | |||||
return false; | |||||
} | |||||
@Override | |||||
public UserAccount getUser(Bytes address, long version) { | |||||
return null; | |||||
} | |||||
} | |||||
private static class EmptyDataAccountSet implements DataAccountQuery{ | |||||
@Override | |||||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public HashDigest getRootHash() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public long getTotalCount() { | |||||
return 0; | |||||
} | |||||
@Override | |||||
public MerkleProof getProof(Bytes address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public DataAccount getDataAccount(Bytes address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public DataAccount getDataAccount(Bytes address, long version) { | |||||
return null; | |||||
} | |||||
} | |||||
private static class EmptyContractAccountSet implements ContractAccountQuery{ | |||||
@Override | |||||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public HashDigest getRootHash() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public long getTotalCount() { | |||||
return 0; | |||||
} | |||||
@Override | |||||
public MerkleProof getProof(Bytes address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public boolean contains(Bytes address) { | |||||
return false; | |||||
} | |||||
@Override | |||||
public ContractAccount getContract(Bytes address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public ContractAccount getContract(Bytes address, long version) { | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,98 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.Set; | |||||
import com.jd.blockchain.ledger.LedgerPermission; | |||||
import com.jd.blockchain.ledger.LedgerSecurityException; | |||||
import com.jd.blockchain.ledger.TransactionPermission; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
class FullPermissionedSecurityManager implements LedgerSecurityManager { | |||||
public static final FullPermissionedSecurityManager INSTANCE = new FullPermissionedSecurityManager(); | |||||
@Override | |||||
public SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) { | |||||
return new FullPermissionedPolicy(endpoints, nodes); | |||||
} | |||||
private static class FullPermissionedPolicy implements SecurityPolicy { | |||||
private Set<Bytes> endpoints; | |||||
private Set<Bytes> nodes; | |||||
public FullPermissionedPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) { | |||||
this.endpoints = endpoints; | |||||
this.nodes = nodes; | |||||
} | |||||
@Override | |||||
public Set<Bytes> getEndpoints() { | |||||
return endpoints; | |||||
} | |||||
@Override | |||||
public Set<Bytes> getNodes() { | |||||
return nodes; | |||||
} | |||||
@Override | |||||
public boolean isEndpointEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) { | |||||
return true; | |||||
} | |||||
@Override | |||||
public boolean isEndpointEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) { | |||||
return true; | |||||
} | |||||
@Override | |||||
public boolean isNodeEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) { | |||||
return true; | |||||
} | |||||
@Override | |||||
public boolean isNodeEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) { | |||||
return true; | |||||
} | |||||
@Override | |||||
public void checkEndpointPermission(LedgerPermission permission, MultiIDsPolicy midPolicy) | |||||
throws LedgerSecurityException { | |||||
} | |||||
@Override | |||||
public void checkEndpointPermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||||
throws LedgerSecurityException { | |||||
} | |||||
@Override | |||||
public void checkNodePermission(LedgerPermission permission, MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||||
} | |||||
@Override | |||||
public void checkNodePermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||||
throws LedgerSecurityException { | |||||
} | |||||
@Override | |||||
public boolean isEndpointValid(MultiIDsPolicy midPolicy) { | |||||
return true; | |||||
} | |||||
@Override | |||||
public boolean isNodeValid(MultiIDsPolicy midPolicy) { | |||||
return true; | |||||
} | |||||
@Override | |||||
public void checkEndpointValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||||
} | |||||
@Override | |||||
public void checkNodeValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||||
} | |||||
} | |||||
} |
@@ -1,22 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
/** | |||||
* @author hhq | |||||
* @version 1.0 | |||||
* @created 14-6��-2018 12:13:32 | |||||
*/ | |||||
public class Gateway extends Node { | |||||
public ParticipantNode m_Participant; | |||||
public Gateway(){ | |||||
} | |||||
public void finalize() throws Throwable { | |||||
super.finalize(); | |||||
} | |||||
} |
@@ -1,3 +1,4 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
//package com.jd.blockchain.ledger.core.impl; | //package com.jd.blockchain.ledger.core.impl; | ||||
// | // | ||||
//import com.jd.blockchain.storage.service.ExPolicyKVStorage; | //import com.jd.blockchain.storage.service.ExPolicyKVStorage; |
@@ -1,356 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.LedgerSetting; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||||
import com.jd.blockchain.crypto.Crypto; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.HashFunction; | |||||
import com.jd.blockchain.ledger.LedgerException; | |||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.Transactional; | |||||
public class LedgerAdminAccount implements Transactional, LedgerAdministration { | |||||
static { | |||||
DataContractRegistry.register(LedgerMetadata.class); | |||||
} | |||||
private static Logger LOGGER = LoggerFactory.getLogger(LedgerAdminAccount.class); | |||||
public static final String LEDGER_META_PREFIX = "MTA" + LedgerConsts.KEY_SEPERATOR; | |||||
public static final String LEDGER_PARTICIPANT_PREFIX = "PAR" + LedgerConsts.KEY_SEPERATOR; | |||||
public static final String LEDGER_PRIVILEGE_PREFIX = "PVL" + LedgerConsts.KEY_SEPERATOR; | |||||
private final Bytes metaPrefix; | |||||
private final Bytes privilegePrefix; | |||||
private LedgerMetadata origMetadata; | |||||
private LedgerMetadataImpl metadata; | |||||
/** | |||||
* 原来的账本设置; | |||||
* | |||||
* <br> | |||||
* 对 LedgerMetadata 修改的新配置不能立即生效,需要达成共识后,在下一次区块计算中才生效; | |||||
*/ | |||||
private LedgerSetting previousSetting; | |||||
/** | |||||
* 账本的参与节点; | |||||
*/ | |||||
private ParticipantDataSet participants; | |||||
// /** | |||||
// * 账本的全局权限设置; | |||||
// */ | |||||
// private PrivilegeDataSet privileges; | |||||
private ExPolicyKVStorage settingsStorage; | |||||
private HashDigest adminAccountHash; | |||||
private boolean readonly; | |||||
private boolean updated; | |||||
public HashDigest getHash() { | |||||
return adminAccountHash; | |||||
} | |||||
public boolean isReadonly() { | |||||
return readonly; | |||||
} | |||||
/** | |||||
* 初始化账本的管理账户; | |||||
* | |||||
* <br> | |||||
* | |||||
* 只在新建账本时调用此方法; | |||||
* | |||||
* @param ledgerSeed | |||||
* @param setting | |||||
* @param partiList | |||||
* @param exPolicyStorage | |||||
* @param versioningStorage | |||||
*/ | |||||
public LedgerAdminAccount(LedgerInitSetting initSetting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||||
VersioningKVStorage versioningStorage) { | |||||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||||
this.privilegePrefix = Bytes.fromString(keyPrefix + LEDGER_PRIVILEGE_PREFIX); | |||||
ParticipantNode[] parties = initSetting.getConsensusParticipants(); | |||||
if (parties.length == 0) { | |||||
throw new LedgerException("No participant!"); | |||||
} | |||||
// 检查参与者列表是否已经按照 id 升序排列,并且 id 不冲突; | |||||
// 注:参与者的 id 要求从 0 开始编号,顺序依次递增,不允许跳空; | |||||
for (int i = 0; i < parties.length; i++) { | |||||
// if (parties[i].getAddress() != i) { | |||||
// throw new LedgerException("The id of participant isn't match the order of the | |||||
// participant list!"); | |||||
// } | |||||
} | |||||
// 初始化元数据; | |||||
this.metadata = new LedgerMetadataImpl(); | |||||
this.metadata.setSeed(initSetting.getLedgerSeed()); | |||||
// 新配置; | |||||
this.metadata.setting = new LedgerConfiguration(initSetting.getConsensusProvider(), | |||||
initSetting.getConsensusSettings(), initSetting.getCryptoSetting()); | |||||
this.previousSetting = new LedgerConfiguration(initSetting.getConsensusProvider(), | |||||
initSetting.getConsensusSettings(), initSetting.getCryptoSetting()); | |||||
this.adminAccountHash = null; | |||||
// 基于原配置初始化参与者列表; | |||||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||||
this.participants = new ParticipantDataSet(previousSetting.getCryptoSetting(), partiPrefix, exPolicyStorage, | |||||
versioningStorage); | |||||
for (ParticipantNode p : parties) { | |||||
this.participants.addConsensusParticipant(p); | |||||
} | |||||
// 初始化其它属性; | |||||
this.settingsStorage = exPolicyStorage; | |||||
this.readonly = false; | |||||
} | |||||
public LedgerAdminAccount(HashDigest adminAccountHash, String keyPrefix, ExPolicyKVStorage kvStorage, | |||||
VersioningKVStorage versioningKVStorage, boolean readonly) { | |||||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||||
this.privilegePrefix = Bytes.fromString(keyPrefix + LEDGER_PRIVILEGE_PREFIX); | |||||
this.settingsStorage = kvStorage; | |||||
this.readonly = readonly; | |||||
this.origMetadata = loadAndVerifySettings(adminAccountHash); | |||||
this.metadata = new LedgerMetadataImpl(origMetadata); | |||||
// 复制记录一份配置作为上一个区块的原始配置,该实例仅供读取,不做修改,也不会回写到存储; | |||||
this.previousSetting = new LedgerConfiguration(metadata.getSetting()); | |||||
this.adminAccountHash = adminAccountHash; | |||||
// this.privileges = new PrivilegeDataSet(metadata.getPrivilegesHash(), | |||||
// metadata.getSetting().getCryptoSetting(), | |||||
// PrefixAppender.prefix(LEDGER_PRIVILEGE_PREFIX, kvStorage), | |||||
// PrefixAppender.prefix(LEDGER_PRIVILEGE_PREFIX, versioningKVStorage), | |||||
// readonly); | |||||
// this.participants = new ParticipantDataSet(metadata.getParticipantsHash(), | |||||
// previousSetting.getCryptoSetting(), | |||||
// PrefixAppender.prefix(LEDGER_PARTICIPANT_PREFIX, kvStorage), | |||||
// PrefixAppender.prefix(LEDGER_PARTICIPANT_PREFIX, versioningKVStorage), | |||||
// readonly); | |||||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||||
this.participants = new ParticipantDataSet(metadata.getParticipantsHash(), previousSetting.getCryptoSetting(), | |||||
partiPrefix, kvStorage, versioningKVStorage, readonly); | |||||
} | |||||
private LedgerMetadata loadAndVerifySettings(HashDigest adminAccountHash) { | |||||
// String base58Hash = adminAccountHash.toBase58(); | |||||
// String key = encodeMetadataKey(base58Hash); | |||||
Bytes key = encodeMetadataKey(adminAccountHash); | |||||
byte[] bytes = settingsStorage.get(key); | |||||
HashFunction hashFunc = Crypto.getHashFunction(adminAccountHash.getAlgorithm()); | |||||
if (!hashFunc.verify(adminAccountHash, bytes)) { | |||||
LOGGER.error("The hash verification of ledger settings fail! --[HASH=" + key + "]"); | |||||
throw new LedgerException("The hash verification of ledger settings fail!"); | |||||
} | |||||
return deserializeMetadata(bytes); | |||||
} | |||||
private Bytes encodeMetadataKey(HashDigest metadataHash) { | |||||
// return LEDGER_META_PREFIX + metadataHash; | |||||
// return metaPrefix + metadataHash; | |||||
return metaPrefix.concat(metadataHash); | |||||
} | |||||
/* | |||||
* (non-Javadoc) | |||||
* | |||||
* @see com.jd.blockchain.ledger.core.LedgerAdministration#getMetadata() | |||||
*/ | |||||
@Override | |||||
public LedgerMetadata getMetadata() { | |||||
return metadata; | |||||
} | |||||
/** | |||||
* 返回原来的账本配置; | |||||
* | |||||
* <br> | |||||
* 此方法总是返回从上一个区块加载的账本配置,即时调用 {@link #setLedgerSetting(LedgerSetting)} 做出了新的更改; | |||||
* | |||||
* @return | |||||
*/ | |||||
public LedgerSetting getPreviousSetting() { | |||||
return previousSetting; | |||||
} | |||||
/** | |||||
* 返回当前设置的账本配置; | |||||
* | |||||
* @return | |||||
*/ | |||||
public LedgerSetting getSetting() { | |||||
return metadata.getSetting(); | |||||
} | |||||
/** | |||||
* 更新账本配置; | |||||
* | |||||
* @param ledgerSetting | |||||
*/ | |||||
public void setLedgerSetting(LedgerSetting ledgerSetting) { | |||||
if (readonly) { | |||||
throw new IllegalArgumentException("This merkle dataset is readonly!"); | |||||
} | |||||
metadata.setSetting(ledgerSetting); | |||||
} | |||||
@Override | |||||
public long getParticipantCount() { | |||||
return participants.getParticipantCount(); | |||||
} | |||||
// /* | |||||
// * (non-Javadoc) | |||||
// * | |||||
// * @see | |||||
// * | |||||
// com.jd.blockchain.ledger.core.LedgerAdministration#getParticipant(java.lang. | |||||
// * String) | |||||
// */ | |||||
// @Override | |||||
// public ParticipantNode getParticipant(int id) { | |||||
// return participants.getParticipant(id); | |||||
// } | |||||
@Override | |||||
public ParticipantNode[] getParticipants() { | |||||
return participants.getParticipants(); | |||||
} | |||||
/** | |||||
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | |||||
* | |||||
* @param participant | |||||
*/ | |||||
public void addParticipant(ParticipantNode participant) { | |||||
participants.addConsensusParticipant(participant); | |||||
} | |||||
@Override | |||||
public boolean isUpdated() { | |||||
return updated || participants.isUpdated(); | |||||
} | |||||
@Override | |||||
public void commit() { | |||||
if (!isUpdated()) { | |||||
return; | |||||
} | |||||
participants.commit(); | |||||
metadata.setParticipantsHash(participants.getRootHash()); | |||||
// 基于之前的密码配置来计算元数据的哈希; | |||||
byte[] metadataBytes = serializeMetadata(metadata); | |||||
HashFunction hashFunc = Crypto | |||||
.getHashFunction(previousSetting.getCryptoSetting().getHashAlgorithm()); | |||||
HashDigest metadataHash = hashFunc.hash(metadataBytes); | |||||
if (adminAccountHash == null || !adminAccountHash.equals(metadataHash)) { | |||||
// update modify; | |||||
// String base58MetadataHash = metadataHash.toBase58(); | |||||
// String metadataKey = encodeMetadataKey(base58MetadataHash); | |||||
Bytes metadataKey = encodeMetadataKey(metadataHash); | |||||
boolean nx = settingsStorage.set(metadataKey, metadataBytes, ExPolicy.NOT_EXISTING); | |||||
if (!nx) { | |||||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||||
// throw new LedgerException( | |||||
// "Ledger metadata already exist! --[LedgerMetadataHash=" + base58MetadataHash | |||||
// + "]"); | |||||
// LOGGER.warn("Ledger metadata already exist! --[MetadataHash=" + | |||||
// base58MetadataHash + "]"); | |||||
} | |||||
adminAccountHash = metadataHash; | |||||
} | |||||
updated = false; | |||||
} | |||||
private LedgerMetadata deserializeMetadata(byte[] bytes) { | |||||
return BinaryProtocol.decode(bytes); | |||||
} | |||||
private byte[] serializeMetadata(LedgerMetadataImpl config) { | |||||
return BinaryProtocol.encode(config, LedgerMetadata.class); | |||||
} | |||||
@Override | |||||
public void cancel() { | |||||
if (!isUpdated()) { | |||||
return; | |||||
} | |||||
participants.cancel(); | |||||
metadata = new LedgerMetadataImpl(origMetadata); | |||||
} | |||||
public static class LedgerMetadataImpl implements LedgerMetadata { | |||||
private byte[] seed; | |||||
private LedgerSetting setting; | |||||
private HashDigest participantsHash; | |||||
public LedgerMetadataImpl() { | |||||
} | |||||
public LedgerMetadataImpl(LedgerMetadata metadata) { | |||||
this.seed = metadata.getSeed(); | |||||
this.setting = metadata.getSetting(); | |||||
this.participantsHash = metadata.getParticipantsHash(); | |||||
} | |||||
@Override | |||||
public byte[] getSeed() { | |||||
return seed; | |||||
} | |||||
@Override | |||||
public LedgerSetting getSetting() { | |||||
return setting; | |||||
} | |||||
@Override | |||||
public HashDigest getParticipantsHash() { | |||||
return participantsHash; | |||||
} | |||||
public void setSeed(byte[] seed) { | |||||
this.seed = seed; | |||||
} | |||||
public void setSetting(LedgerSetting setting) { | |||||
// copy a new instance; | |||||
this.setting = new LedgerConfiguration(setting); | |||||
} | |||||
public void setParticipantsHash(HashDigest participantsHash) { | |||||
this.participantsHash = participantsHash; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.ParticipantDataQuery; | |||||
public interface LedgerAdminDataQuery { | |||||
LedgerAdminInfo getAdminInfo(); | |||||
ParticipantDataQuery getParticipantDataset(); | |||||
} |
@@ -0,0 +1,469 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||||
import com.jd.blockchain.crypto.Crypto; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.HashFunction; | |||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.LedgerException; | |||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.LedgerMetadata_V2; | |||||
import com.jd.blockchain.ledger.LedgerSettings; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||||
import com.jd.blockchain.ledger.UserRolesSettings; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.Transactional; | |||||
public class LedgerAdminDataset implements Transactional, LedgerAdminDataQuery, LedgerAdminInfo { | |||||
static { | |||||
DataContractRegistry.register(LedgerMetadata.class); | |||||
DataContractRegistry.register(LedgerMetadata_V2.class); | |||||
} | |||||
private static Logger LOGGER = LoggerFactory.getLogger(LedgerAdminDataset.class); | |||||
public static final String LEDGER_META_PREFIX = "MTA" + LedgerConsts.KEY_SEPERATOR; | |||||
public static final String LEDGER_PARTICIPANT_PREFIX = "PAR" + LedgerConsts.KEY_SEPERATOR; | |||||
public static final String LEDGER_SETTING_PREFIX = "SET" + LedgerConsts.KEY_SEPERATOR; | |||||
public static final String ROLE_PRIVILEGE_PREFIX = "RPV" + LedgerConsts.KEY_SEPERATOR; | |||||
public static final String USER_ROLE_PREFIX = "URO" + LedgerConsts.KEY_SEPERATOR; | |||||
private final Bytes metaPrefix; | |||||
private final Bytes settingPrefix; | |||||
private LedgerMetadata_V2 origMetadata; | |||||
private LedgerMetadataInfo metadata; | |||||
/** | |||||
* 原来的账本设置; | |||||
* | |||||
* <br> | |||||
* 对 LedgerMetadata 修改的新配置不能立即生效,需要达成共识后,在下一次区块计算中才生效; | |||||
*/ | |||||
private LedgerSettings previousSettings; | |||||
private HashDigest previousSettingHash; | |||||
/** | |||||
* 账本的参与节点; | |||||
*/ | |||||
private ParticipantDataset participants; | |||||
/** | |||||
* “角色-权限”数据集; | |||||
*/ | |||||
private RolePrivilegeDataset rolePrivileges; | |||||
/** | |||||
* “用户-角色”数据集; | |||||
*/ | |||||
private UserRoleDataset userRoles; | |||||
/** | |||||
* 账本参数配置; | |||||
*/ | |||||
private LedgerSettings settings; | |||||
private ExPolicyKVStorage storage; | |||||
private HashDigest adminDataHash; | |||||
private boolean readonly; | |||||
private boolean updated; | |||||
public HashDigest getHash() { | |||||
return adminDataHash; | |||||
} | |||||
public boolean isReadonly() { | |||||
return readonly; | |||||
} | |||||
void setReadonly() { | |||||
this.readonly = true; | |||||
} | |||||
public LedgerSettings getPreviousSetting() { | |||||
return previousSettings; | |||||
} | |||||
@Override | |||||
public RolePrivilegeSettings getRolePrivileges() { | |||||
return rolePrivileges; | |||||
} | |||||
@Override | |||||
public UserRolesSettings getUserRoles() { | |||||
return userRoles; | |||||
} | |||||
@Override | |||||
public LedgerAdminInfo getAdminInfo() { | |||||
return this; | |||||
} | |||||
/** | |||||
* 初始化账本的管理账户; | |||||
* | |||||
* <br> | |||||
* | |||||
* 只在新建账本时调用此方法; | |||||
* | |||||
* @param ledgerSeed | |||||
* @param settings | |||||
* @param partiList | |||||
* @param exPolicyStorage | |||||
* @param versioningStorage | |||||
*/ | |||||
public LedgerAdminDataset(LedgerInitSetting initSetting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||||
VersioningKVStorage versioningStorage) { | |||||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||||
ParticipantNode[] parties = initSetting.getConsensusParticipants(); | |||||
if (parties.length == 0) { | |||||
throw new LedgerException("No participant!"); | |||||
} | |||||
// 初始化元数据; | |||||
this.metadata = new LedgerMetadataInfo(); | |||||
this.metadata.setSeed(initSetting.getLedgerSeed()); | |||||
// 新配置; | |||||
this.settings = new LedgerConfiguration(initSetting.getConsensusProvider(), initSetting.getConsensusSettings(), | |||||
initSetting.getCryptoSetting()); | |||||
this.previousSettings = new LedgerConfiguration(settings); | |||||
this.previousSettingHash = null; | |||||
this.adminDataHash = null; | |||||
// 基于原配置初始化参与者列表; | |||||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||||
this.participants = new ParticipantDataset(previousSettings.getCryptoSetting(), partiPrefix, exPolicyStorage, | |||||
versioningStorage); | |||||
for (ParticipantNode p : parties) { | |||||
this.participants.addConsensusParticipant(p); | |||||
} | |||||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||||
this.rolePrivileges = new RolePrivilegeDataset(this.settings.getCryptoSetting(), rolePrivilegePrefix, | |||||
exPolicyStorage, versioningStorage); | |||||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||||
this.userRoles = new UserRoleDataset(this.settings.getCryptoSetting(), userRolePrefix, exPolicyStorage, | |||||
versioningStorage); | |||||
// 初始化其它属性; | |||||
this.storage = exPolicyStorage; | |||||
this.readonly = false; | |||||
} | |||||
public LedgerAdminDataset(HashDigest adminAccountHash, String keyPrefix, ExPolicyKVStorage kvStorage, | |||||
VersioningKVStorage versioningKVStorage, boolean readonly) { | |||||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||||
this.storage = kvStorage; | |||||
this.readonly = readonly; | |||||
this.origMetadata = loadAndVerifyMetadata(adminAccountHash); | |||||
this.metadata = new LedgerMetadataInfo(origMetadata); | |||||
this.settings = loadAndVerifySettings(metadata.getSettingsHash()); | |||||
// 复制记录一份配置作为上一个区块的原始配置,该实例仅供读取,不做修改,也不会回写到存储; | |||||
this.previousSettings = new LedgerConfiguration(settings); | |||||
this.previousSettingHash = metadata.getSettingsHash(); | |||||
this.adminDataHash = adminAccountHash; | |||||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||||
this.participants = new ParticipantDataset(metadata.getParticipantsHash(), previousSettings.getCryptoSetting(), | |||||
partiPrefix, kvStorage, versioningKVStorage, readonly); | |||||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||||
this.rolePrivileges = new RolePrivilegeDataset(metadata.getRolePrivilegesHash(), | |||||
previousSettings.getCryptoSetting(), rolePrivilegePrefix, kvStorage, versioningKVStorage, readonly); | |||||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||||
this.userRoles = new UserRoleDataset(metadata.getUserRolesHash(), previousSettings.getCryptoSetting(), | |||||
userRolePrefix, kvStorage, versioningKVStorage, readonly); | |||||
} | |||||
private LedgerSettings loadAndVerifySettings(HashDigest settingsHash) { | |||||
if (settingsHash == null) { | |||||
return null; | |||||
} | |||||
Bytes key = encodeSettingsKey(settingsHash); | |||||
byte[] bytes = storage.get(key); | |||||
HashFunction hashFunc = Crypto.getHashFunction(settingsHash.getAlgorithm()); | |||||
if (!hashFunc.verify(settingsHash, bytes)) { | |||||
String errorMsg = "Verification of the hash for ledger setting failed! --[HASH=" + key + "]"; | |||||
LOGGER.error(errorMsg); | |||||
throw new LedgerException(errorMsg); | |||||
} | |||||
return deserializeSettings(bytes); | |||||
} | |||||
private LedgerSettings deserializeSettings(byte[] bytes) { | |||||
return BinaryProtocol.decode(bytes); | |||||
} | |||||
private byte[] serializeSetting(LedgerSettings setting) { | |||||
return BinaryProtocol.encode(setting, LedgerSettings.class); | |||||
} | |||||
private LedgerMetadata_V2 loadAndVerifyMetadata(HashDigest adminAccountHash) { | |||||
Bytes key = encodeMetadataKey(adminAccountHash); | |||||
byte[] bytes = storage.get(key); | |||||
HashFunction hashFunc = Crypto.getHashFunction(adminAccountHash.getAlgorithm()); | |||||
if (!hashFunc.verify(adminAccountHash, bytes)) { | |||||
String errorMsg = "Verification of the hash for ledger metadata failed! --[HASH=" + key + "]"; | |||||
LOGGER.error(errorMsg); | |||||
throw new LedgerException(errorMsg); | |||||
} | |||||
return deserializeMetadata(bytes); | |||||
} | |||||
private Bytes encodeSettingsKey(HashDigest settingsHash) { | |||||
return settingPrefix.concat(settingsHash); | |||||
} | |||||
private Bytes encodeMetadataKey(HashDigest metadataHash) { | |||||
// return LEDGER_META_PREFIX + metadataHash; | |||||
// return metaPrefix + metadataHash; | |||||
return metaPrefix.concat(metadataHash); | |||||
} | |||||
/* | |||||
* (non-Javadoc) | |||||
* | |||||
* @see com.jd.blockchain.ledger.core.LedgerAdministration#getMetadata() | |||||
*/ | |||||
@Override | |||||
public LedgerMetadata_V2 getMetadata() { | |||||
return metadata; | |||||
} | |||||
// /** | |||||
// * 返回原来的账本配置; | |||||
// * | |||||
// * <br> | |||||
// * 此方法总是返回从上一个区块加载的账本配置,即时调用 {@link #setLedgerSetting(LedgerSettings)} 做出了新的更改; | |||||
// * | |||||
// * @return | |||||
// */ | |||||
// public LedgerSettings getPreviousSetting() { | |||||
// return previousSettings; | |||||
// } | |||||
/** | |||||
* 返回当前设置的账本配置; | |||||
* | |||||
* @return | |||||
*/ | |||||
public LedgerSettings getSettings() { | |||||
return settings; | |||||
} | |||||
/** | |||||
* 更新账本配置; | |||||
* | |||||
* @param ledgerSetting | |||||
*/ | |||||
public void setLedgerSetting(LedgerSettings ledgerSetting) { | |||||
if (readonly) { | |||||
throw new IllegalArgumentException("This merkle dataset is readonly!"); | |||||
} | |||||
settings = ledgerSetting; | |||||
updated = true; | |||||
} | |||||
@Override | |||||
public long getParticipantCount() { | |||||
return participants.getParticipantCount(); | |||||
} | |||||
@Override | |||||
public ParticipantNode[] getParticipants() { | |||||
return participants.getParticipants(); | |||||
} | |||||
@Override | |||||
public ParticipantDataset getParticipantDataset() { | |||||
return participants; | |||||
} | |||||
/** | |||||
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | |||||
* | |||||
* @param participant | |||||
*/ | |||||
public void addParticipant(ParticipantNode participant) { | |||||
participants.addConsensusParticipant(participant); | |||||
} | |||||
@Override | |||||
public boolean isUpdated() { | |||||
return updated || participants.isUpdated() || rolePrivileges.isUpdated() || userRoles.isUpdated(); | |||||
} | |||||
@Override | |||||
public void commit() { | |||||
if (!isUpdated()) { | |||||
return; | |||||
} | |||||
// 计算并更新参与方集合的根哈希; | |||||
participants.commit(); | |||||
metadata.setParticipantsHash(participants.getRootHash()); | |||||
// 计算并更新角色权限集合的根哈希; | |||||
rolePrivileges.commit(); | |||||
metadata.setRolePrivilegesHash(rolePrivileges.getRootHash()); | |||||
// 计算并更新用户角色授权集合的根哈希; | |||||
userRoles.commit(); | |||||
metadata.setUserRolesHash(userRoles.getRootHash()); | |||||
// 当前区块上下文的密码参数设置的哈希函数; | |||||
HashFunction hashFunc = Crypto.getHashFunction(previousSettings.getCryptoSetting().getHashAlgorithm()); | |||||
// 计算并更新参数配置的哈希; | |||||
if (settings == null) { | |||||
throw new LedgerException("Missing ledger settings!"); | |||||
} | |||||
byte[] settingsBytes = serializeSetting(settings); | |||||
HashDigest settingsHash = hashFunc.hash(settingsBytes); | |||||
metadata.setSettingsHash(settingsHash); | |||||
if (previousSettingHash == null || !previousSettingHash.equals(settingsHash)) { | |||||
Bytes settingsKey = encodeSettingsKey(settingsHash); | |||||
boolean nx = storage.set(settingsKey, settingsBytes, ExPolicy.NOT_EXISTING); | |||||
if (!nx) { | |||||
String base58MetadataHash = settingsHash.toBase58(); | |||||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||||
LOGGER.warn(errMsg); | |||||
throw new LedgerException(errMsg); | |||||
} | |||||
} | |||||
// 基于之前的密码配置来计算元数据的哈希; | |||||
byte[] metadataBytes = serializeMetadata(metadata); | |||||
HashDigest metadataHash = hashFunc.hash(metadataBytes); | |||||
if (adminDataHash == null || !adminDataHash.equals(metadataHash)) { | |||||
// update modify; | |||||
// String base58MetadataHash = metadataHash.toBase58(); | |||||
// String metadataKey = encodeMetadataKey(base58MetadataHash); | |||||
Bytes metadataKey = encodeMetadataKey(metadataHash); | |||||
boolean nx = storage.set(metadataKey, metadataBytes, ExPolicy.NOT_EXISTING); | |||||
if (!nx) { | |||||
String base58MetadataHash = metadataHash.toBase58(); | |||||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||||
LOGGER.warn(errMsg); | |||||
throw new LedgerException(errMsg); | |||||
} | |||||
adminDataHash = metadataHash; | |||||
} | |||||
updated = false; | |||||
} | |||||
private LedgerMetadata_V2 deserializeMetadata(byte[] bytes) { | |||||
return BinaryProtocol.decode(bytes); | |||||
} | |||||
private byte[] serializeMetadata(LedgerMetadataInfo config) { | |||||
return BinaryProtocol.encode(config, LedgerMetadata_V2.class); | |||||
} | |||||
@Override | |||||
public void cancel() { | |||||
if (!isUpdated()) { | |||||
return; | |||||
} | |||||
participants.cancel(); | |||||
metadata =origMetadata == null ? new LedgerMetadataInfo() : new LedgerMetadataInfo(origMetadata); | |||||
} | |||||
public static class LedgerMetadataInfo implements LedgerMetadata_V2 { | |||||
private byte[] seed; | |||||
// private LedgerSetting setting; | |||||
private HashDigest participantsHash; | |||||
private HashDigest settingsHash; | |||||
private HashDigest rolePrivilegesHash; | |||||
private HashDigest userRolesHash; | |||||
public LedgerMetadataInfo() { | |||||
} | |||||
public LedgerMetadataInfo(LedgerMetadata_V2 metadata) { | |||||
this.seed = metadata.getSeed(); | |||||
this.participantsHash = metadata.getParticipantsHash(); | |||||
this.settingsHash = metadata.getSettingsHash(); | |||||
this.rolePrivilegesHash = metadata.getRolePrivilegesHash(); | |||||
this.userRolesHash = metadata.getUserRolesHash(); | |||||
} | |||||
@Override | |||||
public byte[] getSeed() { | |||||
return seed; | |||||
} | |||||
@Override | |||||
public HashDigest getSettingsHash() { | |||||
return settingsHash; | |||||
} | |||||
@Override | |||||
public HashDigest getParticipantsHash() { | |||||
return participantsHash; | |||||
} | |||||
@Override | |||||
public HashDigest getRolePrivilegesHash() { | |||||
return rolePrivilegesHash; | |||||
} | |||||
@Override | |||||
public HashDigest getUserRolesHash() { | |||||
return userRolesHash; | |||||
} | |||||
public void setSeed(byte[] seed) { | |||||
this.seed = seed; | |||||
} | |||||
public void setSettingsHash(HashDigest settingHash) { | |||||
this.settingsHash = settingHash; | |||||
} | |||||
public void setParticipantsHash(HashDigest participantsHash) { | |||||
this.participantsHash = participantsHash; | |||||
} | |||||
public void setRolePrivilegesHash(HashDigest rolePrivilegesHash) { | |||||
this.rolePrivilegesHash = rolePrivilegesHash; | |||||
} | |||||
public void setUserRolesHash(HashDigest userRolesHash) { | |||||
this.userRolesHash = userRolesHash; | |||||
} | |||||
} | |||||
} |
@@ -1,5 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public enum LedgerAdminPrivilege { | |||||
} |
@@ -1,16 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
public interface LedgerAdministration { | |||||
LedgerMetadata getMetadata(); | |||||
long getParticipantCount(); | |||||
// ParticipantNode getParticipant(int id); | |||||
ParticipantNode[] getParticipants(); | |||||
} |
@@ -1,4 +1,4 @@ | |||||
package com.jd.blockchain.ledger.core.impl; | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | import com.jd.blockchain.binaryproto.DataContractRegistry; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
@@ -33,7 +33,9 @@ public class LedgerBlockData implements LedgerBlock { | |||||
// private HashDigest contractPrivilegeHash; | // private HashDigest contractPrivilegeHash; | ||||
private HashDigest transactionSetHash; | private HashDigest transactionSetHash; | ||||
private long timestamp; | |||||
public LedgerBlockData() { | public LedgerBlockData() { | ||||
} | } | ||||
@@ -155,4 +157,14 @@ public class LedgerBlockData implements LedgerBlock { | |||||
this.ledgerHash = ledgerHash; | this.ledgerHash = ledgerHash; | ||||
} | } | ||||
public long getTimestamp() { | |||||
return timestamp; | |||||
} | |||||
public void setTimestamp(long timestamp) { | |||||
this.timestamp = timestamp; | |||||
} | |||||
} | } |
@@ -1,10 +1,10 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.LedgerSetting; | |||||
import com.jd.blockchain.ledger.LedgerSettings; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
public class LedgerConfiguration implements LedgerSetting { | |||||
public class LedgerConfiguration implements LedgerSettings { | |||||
private String consensusProvider; | private String consensusProvider; | ||||
@@ -16,7 +16,7 @@ public class LedgerConfiguration implements LedgerSetting { | |||||
this.cryptoSetting = new CryptoConfig(); | this.cryptoSetting = new CryptoConfig(); | ||||
} | } | ||||
public LedgerConfiguration(LedgerSetting origSetting) { | |||||
public LedgerConfiguration(LedgerSettings origSetting) { | |||||
if (origSetting != null) { | if (origSetting != null) { | ||||
this.consensusProvider = origSetting.getConsensusProvider(); | this.consensusProvider = origSetting.getConsensusProvider(); | ||||
this.consensusSetting = origSetting.getConsensusSetting(); | this.consensusSetting = origSetting.getConsensusSetting(); | ||||
@@ -0,0 +1,19 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
/** | |||||
* {@link LedgerDataset} 表示账本在某一个区块上的数据集合; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public interface LedgerDataQuery{ | |||||
LedgerAdminDataQuery getAdminDataset(); | |||||
UserAccountQuery getUserAccountSet(); | |||||
DataAccountQuery getDataAccountSet(); | |||||
ContractAccountQuery getContractAccountset(); | |||||
} |
@@ -1,21 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
/** | |||||
* {@link LedgerDataSet} 表示账本在某一个区块上的数据集合; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public interface LedgerDataSet{ | |||||
boolean isReadonly(); | |||||
LedgerAdminAccount getAdminAccount(); | |||||
UserAccountSet getUserAccountSet(); | |||||
DataAccountSet getDataAccountSet(); | |||||
ContractAccountSet getContractAccountSet(); | |||||
} |
@@ -1,33 +1,31 @@ | |||||
package com.jd.blockchain.ledger.core.impl; | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.core.*; | |||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||||
public class LedgerDataset implements LedgerDataQuery, Transactional { | |||||
private LedgerAdminAccount adminAccount; | |||||
private LedgerAdminDataset adminDataset; | |||||
private UserAccountSet userAccountSet; | private UserAccountSet userAccountSet; | ||||
private DataAccountSet dataAccountSet; | private DataAccountSet dataAccountSet; | ||||
private ContractAccountSet contractAccountSet; | private ContractAccountSet contractAccountSet; | ||||
private boolean readonly; | |||||
private boolean readonly; | |||||
/** | /** | ||||
* Create new block; | * Create new block; | ||||
* | |||||
* @param adminAccount | * @param adminAccount | ||||
* @param userAccountSet | * @param userAccountSet | ||||
* @param dataAccountSet | * @param dataAccountSet | ||||
* @param contractAccountSet | * @param contractAccountSet | ||||
* @param readonly | * @param readonly | ||||
*/ | */ | ||||
public LedgerDataSetImpl(LedgerAdminAccount adminAccount, | |||||
UserAccountSet userAccountSet, DataAccountSet dataAccountSet, ContractAccountSet contractAccountSet, | |||||
boolean readonly) { | |||||
this.adminAccount = adminAccount; | |||||
public LedgerDataset(LedgerAdminDataset adminAccount, UserAccountSet userAccountSet, | |||||
DataAccountSet dataAccountSet, ContractAccountSet contractAccountSet, boolean readonly) { | |||||
this.adminDataset = adminAccount; | |||||
this.userAccountSet = userAccountSet; | this.userAccountSet = userAccountSet; | ||||
this.dataAccountSet = dataAccountSet; | this.dataAccountSet = dataAccountSet; | ||||
this.contractAccountSet = contractAccountSet; | this.contractAccountSet = contractAccountSet; | ||||
@@ -36,8 +34,8 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||||
} | } | ||||
@Override | @Override | ||||
public LedgerAdminAccount getAdminAccount() { | |||||
return adminAccount; | |||||
public LedgerAdminDataset getAdminDataset() { | |||||
return adminDataset; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -51,13 +49,13 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||||
} | } | ||||
@Override | @Override | ||||
public ContractAccountSet getContractAccountSet() { | |||||
public ContractAccountSet getContractAccountset() { | |||||
return contractAccountSet; | return contractAccountSet; | ||||
} | } | ||||
@Override | @Override | ||||
public boolean isUpdated() { | public boolean isUpdated() { | ||||
return adminAccount.isUpdated() || userAccountSet.isUpdated() || dataAccountSet.isUpdated() | |||||
return adminDataset.isUpdated() || userAccountSet.isUpdated() || dataAccountSet.isUpdated() | |||||
|| contractAccountSet.isUpdated(); | || contractAccountSet.isUpdated(); | ||||
} | } | ||||
@@ -70,7 +68,7 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||||
return; | return; | ||||
} | } | ||||
adminAccount.commit(); | |||||
adminDataset.commit(); | |||||
userAccountSet.commit(); | userAccountSet.commit(); | ||||
dataAccountSet.commit(); | dataAccountSet.commit(); | ||||
contractAccountSet.commit(); | contractAccountSet.commit(); | ||||
@@ -78,15 +76,22 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||||
@Override | @Override | ||||
public void cancel() { | public void cancel() { | ||||
adminAccount.cancel(); | |||||
adminDataset.cancel(); | |||||
userAccountSet.cancel(); | userAccountSet.cancel(); | ||||
dataAccountSet.cancel(); | dataAccountSet.cancel(); | ||||
contractAccountSet.cancel(); | contractAccountSet.cancel(); | ||||
} | } | ||||
@Override | |||||
public boolean isReadonly() { | public boolean isReadonly() { | ||||
return readonly; | return readonly; | ||||
} | } | ||||
void setReadonly() { | |||||
this.readonly = true; | |||||
this.adminDataset.setReadonly(); | |||||
this.userAccountSet.setReadonly(); | |||||
this.dataAccountSet.setReadonly(); | |||||
this.contractAccountSet.setReadonly(); | |||||
} | |||||
} | } |
@@ -1,5 +1,6 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerException; | import com.jd.blockchain.ledger.LedgerException; | ||||
import com.jd.blockchain.ledger.LedgerTransaction; | import com.jd.blockchain.ledger.LedgerTransaction; | ||||
@@ -10,7 +11,7 @@ import com.jd.blockchain.ledger.TransactionRequest; | |||||
* <p> | * <p> | ||||
* | * | ||||
* {@link LedgerEditor} 以上一个区块作为数据编辑的起点; <br> | * {@link LedgerEditor} 以上一个区块作为数据编辑的起点; <br> | ||||
* 对账本数据({@link #getDataSet()})的批量更改可以作为一个交易({@link LedgerTransaction})整体提交暂存,形成暂存点; | |||||
* 对账本数据({@link #getDataset()})的批量更改可以作为一个交易({@link LedgerTransaction})整体提交暂存,形成暂存点; | |||||
* <br> | * <br> | ||||
* | * | ||||
* @author huanghaiquan | * @author huanghaiquan | ||||
@@ -18,11 +19,39 @@ import com.jd.blockchain.ledger.TransactionRequest; | |||||
*/ | */ | ||||
public interface LedgerEditor { | public interface LedgerEditor { | ||||
/** | |||||
* 账本Hash; | |||||
* | |||||
* @return | |||||
*/ | |||||
HashDigest getLedgerHash(); | |||||
/** | |||||
* 新区块的高度; | |||||
* | |||||
* @return | |||||
*/ | |||||
long getBlockHeight(); | |||||
/** | |||||
* 最新的账本数据集; | |||||
* | |||||
* @return | |||||
*/ | |||||
LedgerDataset getLedgerDataset(); | |||||
/** | |||||
* 最新的交易集合; | |||||
* | |||||
* @return | |||||
*/ | |||||
TransactionSet getTransactionSet(); | |||||
/** | /** | ||||
* 开始新事务;<br> | * 开始新事务;<br> | ||||
* | * | ||||
* 方法返回之前,将会校验交易请求的用户签名列表和节点签名列表,并在后续对数据集 | * 方法返回之前,将会校验交易请求的用户签名列表和节点签名列表,并在后续对数据集 | ||||
* {@link LedgerTransactionContext#getDataSet()} 的操作时,校验这些用户和节点是否具备权限;<br> | |||||
* {@link LedgerTransactionContext#getDataset()} 的操作时,校验这些用户和节点是否具备权限;<br> | |||||
* | * | ||||
* 校验失败将引发异常 {@link LedgerException}; | * 校验失败将引发异常 {@link LedgerException}; | ||||
* <p> | * <p> | ||||
@@ -32,11 +61,15 @@ public interface LedgerEditor { | |||||
* 或者全部回滚(通过方法 {@link LedgerTransactionContext#rollback()}),以此实现原子性写入; | * 或者全部回滚(通过方法 {@link LedgerTransactionContext#rollback()}),以此实现原子性写入; | ||||
* <p> | * <p> | ||||
* | * | ||||
* 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存;<p> | |||||
* 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存; | |||||
* <p> | |||||
* | |||||
* | |||||
* | * | ||||
* 注:方法不解析、不执行交易中的操作; | * 注:方法不解析、不执行交易中的操作; | ||||
* <p> | |||||
* | * | ||||
* @param txRequest | |||||
* @param txRequest 交易请求; | |||||
* @return | * @return | ||||
*/ | */ | ||||
LedgerTransactionContext newTransaction(TransactionRequest txRequest); | LedgerTransactionContext newTransaction(TransactionRequest txRequest); | ||||
@@ -13,8 +13,8 @@ import com.jd.blockchain.ledger.LedgerInitOperation; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
@DataContract(code = DataCodes.METADATA_INIT_PERMISSION) | |||||
public interface LedgerInitPermission { | |||||
@DataContract(code = DataCodes.METADATA_INIT_PROPOSAL) | |||||
public interface LedgerInitProposal { | |||||
/** | /** | ||||
* 做出许可的参与方 ID; | * 做出许可的参与方 ID; |
@@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | import com.jd.blockchain.crypto.SignatureDigest; | ||||
public class LedgerInitPermissionData implements LedgerInitPermission { | |||||
public class LedgerInitProposalData implements LedgerInitProposal { | |||||
private int participantId; | private int participantId; | ||||
@@ -11,10 +11,11 @@ public class LedgerInitPermissionData implements LedgerInitPermission { | |||||
/** | /** | ||||
* a private contructor for deserialize; | * a private contructor for deserialize; | ||||
*/ | */ | ||||
private LedgerInitPermissionData() { | |||||
@SuppressWarnings("unused") | |||||
private LedgerInitProposalData() { | |||||
} | } | ||||
public LedgerInitPermissionData(int participantId, SignatureDigest initTxSignature) { | |||||
public LedgerInitProposalData(int participantId, SignatureDigest initTxSignature) { | |||||
this.participantId = participantId; | this.participantId = participantId; | ||||
this.transactionSignature = initTxSignature; | this.transactionSignature = initTxSignature; | ||||
} | } |
@@ -0,0 +1,215 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.SignatureDigest; | |||||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||||
import com.jd.blockchain.ledger.DigitalSignature; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerInitException; | |||||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.RoleInitSettings; | |||||
import com.jd.blockchain.ledger.RolesConfigureOperation; | |||||
import com.jd.blockchain.ledger.SecurityInitSettings; | |||||
import com.jd.blockchain.ledger.TransactionBuilder; | |||||
import com.jd.blockchain.ledger.TransactionContent; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
import com.jd.blockchain.ledger.UserAuthInitSettings; | |||||
import com.jd.blockchain.ledger.UserAuthorizeOperation; | |||||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||||
import com.jd.blockchain.service.TransactionBatchResultHandle; | |||||
import com.jd.blockchain.storage.service.KVStorageService; | |||||
import com.jd.blockchain.transaction.SignatureUtils; | |||||
import com.jd.blockchain.transaction.TxBuilder; | |||||
import com.jd.blockchain.transaction.TxRequestBuilder; | |||||
public class LedgerInitializer { | |||||
private static final FullPermissionedSecurityManager FULL_PERMISSION_SECURITY_MANAGER = new FullPermissionedSecurityManager(); | |||||
private static final LedgerDataQuery EMPTY_LEDGER_DATA_QUERY = new EmptyLedgerDataset(); | |||||
private static final OperationHandleRegisteration DEFAULT_OP_HANDLE_REG = new DefaultOperationHandleRegisteration(); | |||||
private LedgerService EMPTY_LEDGERS = new LedgerManager(); | |||||
private LedgerInitSetting initSetting; | |||||
private TransactionContent initTxContent; | |||||
private volatile LedgerBlock genesisBlock; | |||||
private volatile LedgerEditor ledgerEditor; | |||||
private volatile boolean committed = false; | |||||
private volatile boolean canceled = false; | |||||
private TransactionBatchResultHandle txResultsHandle; | |||||
/** | |||||
* 初始化生成的账本hash; <br> | |||||
* | |||||
* 在成功执行 {@link #prepareLedger(KVStorageService, DigitalSignature...)} 之前总是返回 | |||||
* null; | |||||
* | |||||
* @return | |||||
*/ | |||||
public HashDigest getLedgerHash() { | |||||
return genesisBlock == null ? null : genesisBlock.getHash(); | |||||
} | |||||
/** | |||||
* @param initSetting | |||||
* @param initTxContent | |||||
*/ | |||||
private LedgerInitializer(LedgerInitSetting initSetting, TransactionContent initTxContent) { | |||||
this.initSetting = initSetting; | |||||
this.initTxContent = initTxContent; | |||||
} | |||||
public TransactionContent getTransactionContent() { | |||||
return initTxContent; | |||||
} | |||||
private static SecurityInitSettings createDefaultSecurityInitSettings() { | |||||
// TODO throw new IllegalStateException("Not implemented!"); | |||||
return null; | |||||
} | |||||
// public static LedgerInitializer create(LedgerInitSetting initSetting) { | |||||
// return create(initSetting, createDefaultSecurityInitSettings()); | |||||
// } | |||||
public static LedgerInitializer create(LedgerInitSetting initSetting, SecurityInitSettings securityInitSettings) { | |||||
// 生成创世交易; | |||||
TransactionContent initTxContent = buildGenesisTransaction(initSetting, securityInitSettings); | |||||
return new LedgerInitializer(initSetting, initTxContent); | |||||
} | |||||
/** | |||||
* 根据初始化配置,生成创始交易; | |||||
* <p> | |||||
* | |||||
* “创世交易”按顺序由以下操作组成:<br> | |||||
* (1) 账本初始化 {@link LedgerInitOperation}:此操作仅用于锚定了原始的交易配置,对应的 | |||||
* {@link OperationHandle} 执行空操作,由“创世交易”其余的操作来表达对账本的实际修改;<br> | |||||
* (2) 注册用户 {@link UserRegisterOperation}:有一项或者多项;<br> | |||||
* (3) 配置角色 {@link RolesConfigureOperation}:有一项或者多项;<br> | |||||
* (4) 授权用户 {@link UserAuthorizeOperation}:有一项或者多项;<br> | |||||
* | |||||
* @param initSetting | |||||
* @param securityInitSettings | |||||
* @return | |||||
*/ | |||||
public static TransactionContent buildGenesisTransaction(LedgerInitSetting initSetting, | |||||
SecurityInitSettings securityInitSettings) { | |||||
// 账本初始化交易的账本 hash 为 null; | |||||
TransactionBuilder initTxBuilder = new TxBuilder(null); | |||||
// 定义账本初始化操作; | |||||
initTxBuilder.ledgers().create(initSetting); | |||||
// TODO: 注册参与方; 目前由 LedgerInitSetting 定义,在 LedgerAdminDataset 中解释执行; | |||||
// 注册用户; | |||||
for (ParticipantNode p : initSetting.getConsensusParticipants()) { | |||||
// TODO:暂时只支持注册用户的初始化操作; | |||||
BlockchainIdentity superUserId = new BlockchainIdentityData(p.getPubKey()); | |||||
initTxBuilder.users().register(superUserId); | |||||
} | |||||
// 配置角色; | |||||
for (RoleInitSettings roleSettings : securityInitSettings.getRoles()) { | |||||
initTxBuilder.security().roles().configure(roleSettings.getRoleName()) | |||||
.enable(roleSettings.getLedgerPermissions()).enable(roleSettings.getTransactionPermissions()); | |||||
} | |||||
// 授权用户; | |||||
for (UserAuthInitSettings userAuthSettings : securityInitSettings.getUserAuthorizations()) { | |||||
initTxBuilder.security().authorziations().forUser(userAuthSettings.getUserAddress()) | |||||
.authorize(userAuthSettings.getRoles()) | |||||
.setPolicy(userAuthSettings.getPolicy()); | |||||
} | |||||
// 账本初始化配置声明的创建时间来初始化交易时间戳;注:不能用本地时间,因为共识节点之间的本地时间系统不一致; | |||||
return initTxBuilder.prepareContent(initSetting.getCreatedTime()); | |||||
} | |||||
public SignatureDigest signTransaction(PrivKey privKey) { | |||||
return SignatureUtils.sign(initTxContent, privKey); | |||||
} | |||||
/** | |||||
* 准备创建账本; | |||||
* | |||||
* @param storageService 存储服务; | |||||
* @param nodeSignatures 节点签名列表; | |||||
* @return | |||||
*/ | |||||
public LedgerBlock prepareLedger(KVStorageService storageService, DigitalSignature... nodeSignatures) { | |||||
if (genesisBlock != null) { | |||||
throw new LedgerInitException("The ledger has been prepared!"); | |||||
} | |||||
// 生成账本; | |||||
this.ledgerEditor = createLedgerEditor(this.initSetting, storageService); | |||||
this.genesisBlock = prepareLedger(ledgerEditor, nodeSignatures); | |||||
return genesisBlock; | |||||
} | |||||
public void commit() { | |||||
if (committed) { | |||||
throw new LedgerInitException("The ledger has been committed!"); | |||||
} | |||||
if (canceled) { | |||||
throw new LedgerInitException("The ledger has been canceled!"); | |||||
} | |||||
committed = true; | |||||
this.txResultsHandle.commit(); | |||||
} | |||||
public void cancel() { | |||||
if (canceled) { | |||||
throw new LedgerInitException("The ledger has been canceled!"); | |||||
} | |||||
if (committed) { | |||||
throw new LedgerInitException("The ledger has been committed!"); | |||||
} | |||||
this.ledgerEditor.cancel(); | |||||
} | |||||
public static LedgerEditor createLedgerEditor(LedgerInitSetting initSetting, KVStorageService storageService) { | |||||
LedgerEditor genesisBlockEditor = LedgerTransactionalEditor.createEditor(initSetting, | |||||
LedgerManage.LEDGER_PREFIX, storageService.getExPolicyKVStorage(), | |||||
storageService.getVersioningKVStorage()); | |||||
return genesisBlockEditor; | |||||
} | |||||
/** | |||||
* 初始化账本数据,返回创始区块; | |||||
* | |||||
* @param ledgerEditor | |||||
* @return | |||||
*/ | |||||
private LedgerBlock prepareLedger(LedgerEditor ledgerEditor, DigitalSignature... nodeSignatures) { | |||||
// 初始化时,自动将参与方注册为账本的用户; | |||||
TxRequestBuilder txReqBuilder = new TxRequestBuilder(this.initTxContent); | |||||
txReqBuilder.addNodeSignature(nodeSignatures); | |||||
TransactionRequest txRequest = txReqBuilder.buildRequest(); | |||||
TransactionBatchProcessor txProcessor = new TransactionBatchProcessor(FULL_PERMISSION_SECURITY_MANAGER, | |||||
ledgerEditor, EMPTY_LEDGER_DATA_QUERY, DEFAULT_OP_HANDLE_REG, EMPTY_LEDGERS); | |||||
txProcessor.schedule(txRequest); | |||||
txResultsHandle = txProcessor.prepare(); | |||||
return txResultsHandle.getBlock(); | |||||
} | |||||
} |
@@ -12,19 +12,21 @@ import com.jd.blockchain.storage.service.KVStorageService; | |||||
*/ | */ | ||||
public interface LedgerManage extends LedgerService { | public interface LedgerManage extends LedgerService { | ||||
static final String LEDGER_PREFIX = "LDG://"; | |||||
LedgerRepository register(HashDigest ledgerHash, KVStorageService storageService); | LedgerRepository register(HashDigest ledgerHash, KVStorageService storageService); | ||||
void unregister(HashDigest ledgerHash); | void unregister(HashDigest ledgerHash); | ||||
/** | |||||
* 创建新账本; | |||||
* | |||||
* @param initSetting | |||||
* 初始化配置; | |||||
* @param initPermissions | |||||
* 参与者的初始化授权列表;与参与者列表一致; | |||||
* @return | |||||
*/ | |||||
LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService); | |||||
// /** | |||||
// * 创建新账本; | |||||
// * | |||||
// * @param initSetting | |||||
// * 初始化配置; | |||||
// * @param initPermissions | |||||
// * 参与者的初始化授权列表;与参与者列表一致; | |||||
// * @return | |||||
// */ | |||||
// LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService); | |||||
} | } |
@@ -1,4 +1,4 @@ | |||||
package com.jd.blockchain.ledger.core.impl; | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
@@ -9,11 +9,6 @@ import com.jd.blockchain.crypto.CryptoProvider; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.LedgerException; | import com.jd.blockchain.ledger.LedgerException; | ||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.core.LedgerConsts; | |||||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||||
import com.jd.blockchain.ledger.core.LedgerManage; | |||||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.KVStorageService; | import com.jd.blockchain.storage.service.KVStorageService; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
@@ -27,8 +22,6 @@ import com.jd.blockchain.utils.codec.Base58Utils; | |||||
*/ | */ | ||||
public class LedgerManager implements LedgerManage { | public class LedgerManager implements LedgerManage { | ||||
private static final String LEDGER_PREFIX = "LDG://"; | |||||
// @Autowired | // @Autowired | ||||
// private ExistentialKVStorage exPolicyStorage; | // private ExistentialKVStorage exPolicyStorage; | ||||
// | // | ||||
@@ -69,7 +62,7 @@ public class LedgerManager implements LedgerManage { | |||||
ledgerVersioningStorage); | ledgerVersioningStorage); | ||||
// 校验 crypto service provider ; | // 校验 crypto service provider ; | ||||
CryptoSetting cryptoSetting = ledgerRepo.getAdminAccount().getSetting().getCryptoSetting(); | |||||
CryptoSetting cryptoSetting = ledgerRepo.getAdminInfo().getSettings().getCryptoSetting(); | |||||
checkCryptoSetting(cryptoSetting, ledgerHash); | checkCryptoSetting(cryptoSetting, ledgerHash); | ||||
// 创建账本上下文; | // 创建账本上下文; | ||||
@@ -142,18 +135,18 @@ public class LedgerManager implements LedgerManage { | |||||
} | } | ||||
} | } | ||||
/* | |||||
* (non-Javadoc) | |||||
* | |||||
* @see com.jd.blockchain.ledger.core.LedgerManager#newLedger(com.jd.blockchain. | |||||
* ledger.core.ConsensusConfig, com.jd.blockchain.ledger.core.CryptoConfig) | |||||
*/ | |||||
@Override | |||||
public LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService) { | |||||
LedgerEditor genesisBlockEditor = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_PREFIX, | |||||
storageService.getExPolicyKVStorage(), storageService.getVersioningKVStorage()); | |||||
return genesisBlockEditor; | |||||
} | |||||
// /* | |||||
// * (non-Javadoc) | |||||
// * | |||||
// * @see com.jd.blockchain.ledger.core.LedgerManager#newLedger(com.jd.blockchain. | |||||
// * ledger.core.ConsensusConfig, com.jd.blockchain.ledger.core.CryptoConfig) | |||||
// */ | |||||
// @Override | |||||
// public LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService) { | |||||
// LedgerEditor genesisBlockEditor = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_PREFIX, | |||||
// storageService.getExPolicyKVStorage(), storageService.getVersioningKVStorage()); | |||||
// return genesisBlockEditor; | |||||
// } | |||||
static String getLedgerStoragePrefix(HashDigest ledgerHash) { | static String getLedgerStoragePrefix(HashDigest ledgerHash) { | ||||
String base58LedgerHash = Base58Utils.encode(ledgerHash.toBytes()); | String base58LedgerHash = Base58Utils.encode(ledgerHash.toBytes()); |
@@ -1,25 +1,33 @@ | |||||
package com.jd.blockchain.ledger.core.impl; | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import com.jd.blockchain.contract.ContractException; | import com.jd.blockchain.contract.ContractException; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||||
import com.jd.blockchain.ledger.core.DataAccount; | |||||
import com.jd.blockchain.ledger.core.DataAccountSet; | |||||
import com.jd.blockchain.ledger.core.LedgerAdministration; | |||||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||||
import com.jd.blockchain.ledger.core.LedgerService; | |||||
import com.jd.blockchain.ledger.core.TransactionSet; | |||||
import com.jd.blockchain.ledger.core.UserAccountSet; | |||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.ContractInfo; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.KVDataObject; | |||||
import com.jd.blockchain.ledger.KVDataVO; | |||||
import com.jd.blockchain.ledger.KVInfoVO; | |||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerInfo; | |||||
import com.jd.blockchain.ledger.LedgerMetadata; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.ledger.UserInfo; | |||||
import com.jd.blockchain.transaction.BlockchainQueryService; | import com.jd.blockchain.transaction.BlockchainQueryService; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.QueryUtil; | import com.jd.blockchain.utils.QueryUtil; | ||||
public class LedgerQueryService implements BlockchainQueryService { | public class LedgerQueryService implements BlockchainQueryService { | ||||
private static final KVDataEntry[] EMPTY_ENTRIES = new KVDataEntry[0]; | |||||
private LedgerService ledgerService; | private LedgerService ledgerService; | ||||
public LedgerQueryService(LedgerService ledgerService) { | public LedgerQueryService(LedgerService ledgerService) { | ||||
@@ -40,15 +48,23 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); | ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); | ||||
return ledgerInfo; | return ledgerInfo; | ||||
} | } | ||||
@Override | |||||
public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | |||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||||
LedgerBlock block = ledger.getLatestBlock(); | |||||
LedgerAdminInfo administration = ledger.getAdminInfo(block); | |||||
return administration; | |||||
} | |||||
@Override | @Override | ||||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { | public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { | ||||
return ledgerAdministration(ledgerHash).getParticipants(); | |||||
return getLedgerAdminInfo(ledgerHash).getParticipants(); | |||||
} | } | ||||
@Override | @Override | ||||
public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { | public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { | ||||
return ledgerAdministration(ledgerHash).getMetadata(); | |||||
return getLedgerAdminInfo(ledgerHash).getMetadata(); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -91,7 +107,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getDataAccountCount(HashDigest ledgerHash, long height) { | public long getDataAccountCount(HashDigest ledgerHash, long height) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getBlock(height); | LedgerBlock block = ledger.getBlock(height); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
return dataAccountSet.getTotalCount(); | return dataAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -99,7 +115,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) { | public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getBlock(blockHash); | LedgerBlock block = ledger.getBlock(blockHash); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
return dataAccountSet.getTotalCount(); | return dataAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -107,7 +123,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getDataAccountTotalCount(HashDigest ledgerHash) { | public long getDataAccountTotalCount(HashDigest ledgerHash) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
return dataAccountSet.getTotalCount(); | return dataAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -115,7 +131,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getUserCount(HashDigest ledgerHash, long height) { | public long getUserCount(HashDigest ledgerHash, long height) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getBlock(height); | LedgerBlock block = ledger.getBlock(height); | ||||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||||
return userAccountSet.getTotalCount(); | return userAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -123,7 +139,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) { | public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getBlock(blockHash); | LedgerBlock block = ledger.getBlock(blockHash); | ||||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||||
return userAccountSet.getTotalCount(); | return userAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -131,7 +147,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getUserTotalCount(HashDigest ledgerHash) { | public long getUserTotalCount(HashDigest ledgerHash) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||||
return userAccountSet.getTotalCount(); | return userAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -139,7 +155,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getContractCount(HashDigest ledgerHash, long height) { | public long getContractCount(HashDigest ledgerHash, long height) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getBlock(height); | LedgerBlock block = ledger.getBlock(height); | ||||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||||
return contractAccountSet.getTotalCount(); | return contractAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -147,7 +163,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) { | public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getBlock(blockHash); | LedgerBlock block = ledger.getBlock(blockHash); | ||||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||||
return contractAccountSet.getTotalCount(); | return contractAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -155,7 +171,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public long getContractTotalCount(HashDigest ledgerHash) { | public long getContractTotalCount(HashDigest ledgerHash) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||||
return contractAccountSet.getTotalCount(); | return contractAccountSet.getTotalCount(); | ||||
} | } | ||||
@@ -238,7 +254,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public UserInfo getUser(HashDigest ledgerHash, String address) { | public UserInfo getUser(HashDigest ledgerHash, String address) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||||
return userAccountSet.getUser(address); | return userAccountSet.getUser(address); | ||||
} | } | ||||
@@ -247,18 +263,18 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { | public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
return dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | return dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | ||||
} | } | ||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | ||||
if (keys == null || keys.length == 0) { | if (keys == null || keys.length == 0) { | ||||
return null; | |||||
return EMPTY_ENTRIES; | |||||
} | } | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | ||||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | KVDataEntry[] entries = new KVDataEntry[keys.length]; | ||||
@@ -266,7 +282,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
for (int i = 0; i < entries.length; i++) { | for (int i = 0; i < entries.length; i++) { | ||||
final String currKey = keys[i]; | final String currKey = keys[i]; | ||||
ver = dataAccount.getDataVersion(Bytes.fromString(currKey)); | |||||
ver = dataAccount == null ? -1 : dataAccount.getDataVersion(Bytes.fromString(currKey)); | |||||
if (ver < 0) { | if (ver < 0) { | ||||
entries[i] = new KVDataObject(currKey, -1, null); | entries[i] = new KVDataObject(currKey, -1, null); | ||||
@@ -306,7 +322,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | ||||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | KVDataEntry[] entries = new KVDataEntry[keys.length]; | ||||
@@ -337,7 +353,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | ||||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); | int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); | ||||
@@ -349,7 +365,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | ||||
return dataAccount.getDataEntriesTotalCount(); | return dataAccount.getDataEntriesTotalCount(); | ||||
@@ -359,7 +375,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public ContractInfo getContract(HashDigest ledgerHash, String address) { | public ContractInfo getContract(HashDigest ledgerHash, String address) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||||
return contractAccountSet.getContract(Bytes.fromBase58(address)); | return contractAccountSet.getContract(Bytes.fromBase58(address)); | ||||
} | } | ||||
@@ -367,7 +383,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) userAccountSet.getTotalCount()); | int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) userAccountSet.getTotalCount()); | ||||
return userAccountSet.getAccounts(pages[0], pages[1]); | return userAccountSet.getAccounts(pages[0], pages[1]); | ||||
} | } | ||||
@@ -376,7 +392,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccountSet.getTotalCount()); | int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccountSet.getTotalCount()); | ||||
return dataAccountSet.getAccounts(pages[0], pages[1]); | return dataAccountSet.getAccounts(pages[0], pages[1]); | ||||
} | } | ||||
@@ -385,15 +401,9 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | ||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) contractAccountSet.getTotalCount()); | int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) contractAccountSet.getTotalCount()); | ||||
return contractAccountSet.getAccounts(pages[0], pages[1]); | return contractAccountSet.getAccounts(pages[0], pages[1]); | ||||
} | } | ||||
private LedgerAdministration ledgerAdministration(HashDigest ledgerHash) { | |||||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||||
LedgerBlock block = ledger.getLatestBlock(); | |||||
LedgerAdministration administration = ledger.getAdminAccount(block); | |||||
return administration; | |||||
} | |||||
} | } |
@@ -3,6 +3,7 @@ package com.jd.blockchain.ledger.core; | |||||
import java.io.Closeable; | import java.io.Closeable; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
public interface LedgerRepository extends Closeable { | public interface LedgerRepository extends Closeable { | ||||
@@ -51,23 +52,23 @@ public interface LedgerRepository extends Closeable { | |||||
*/ | */ | ||||
LedgerBlock getBlock(long height); | LedgerBlock getBlock(long height); | ||||
LedgerAdministration getAdminInfo(); | |||||
LedgerAdminInfo getAdminInfo(); | |||||
LedgerAdminInfo getAdminInfo(LedgerBlock block); | |||||
LedgerBlock getBlock(HashDigest hash); | LedgerBlock getBlock(HashDigest hash); | ||||
LedgerDataSet getDataSet(LedgerBlock block); | |||||
LedgerDataQuery getDataSet(LedgerBlock block); | |||||
TransactionSet getTransactionSet(LedgerBlock block); | TransactionSet getTransactionSet(LedgerBlock block); | ||||
LedgerAdminAccount getAdminAccount(LedgerBlock block); | |||||
UserAccountQuery getUserAccountSet(LedgerBlock block); | |||||
UserAccountSet getUserAccountSet(LedgerBlock block); | |||||
DataAccountQuery getDataAccountSet(LedgerBlock block); | |||||
DataAccountSet getDataAccountSet(LedgerBlock block); | |||||
ContractAccountQuery getContractAccountSet(LedgerBlock block); | |||||
ContractAccountSet getContractAccountSet(LedgerBlock block); | |||||
default LedgerDataSet getDataSet() { | |||||
default LedgerDataQuery getDataSet() { | |||||
return getDataSet(getLatestBlock()); | return getDataSet(getLatestBlock()); | ||||
} | } | ||||
@@ -75,19 +76,15 @@ public interface LedgerRepository extends Closeable { | |||||
return getTransactionSet(getLatestBlock()); | return getTransactionSet(getLatestBlock()); | ||||
} | } | ||||
default LedgerAdminAccount getAdminAccount() { | |||||
return getAdminAccount(getLatestBlock()); | |||||
} | |||||
default UserAccountSet getUserAccountSet() { | |||||
default UserAccountQuery getUserAccountSet() { | |||||
return getUserAccountSet(getLatestBlock()); | return getUserAccountSet(getLatestBlock()); | ||||
} | } | ||||
default DataAccountSet getDataAccountSet() { | |||||
default DataAccountQuery getDataAccountSet() { | |||||
return getDataAccountSet(getLatestBlock()); | return getDataAccountSet(getLatestBlock()); | ||||
} | } | ||||
default ContractAccountSet getContractAccountSet() { | |||||
default ContractAccountQuery getContractAccountSet() { | |||||
return getContractAccountSet(getLatestBlock()); | return getContractAccountSet(getLatestBlock()); | ||||
} | } | ||||
@@ -1,22 +1,17 @@ | |||||
package com.jd.blockchain.ledger.core.impl; | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.crypto.Crypto; | import com.jd.blockchain.crypto.Crypto; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.HashFunction; | import com.jd.blockchain.crypto.HashFunction; | ||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.ledger.core.AccountAccessPolicy; | |||||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||||
import com.jd.blockchain.ledger.core.DataAccountSet; | |||||
import com.jd.blockchain.ledger.core.LedgerAdminAccount; | |||||
import com.jd.blockchain.ledger.core.LedgerAdministration; | |||||
import com.jd.blockchain.ledger.core.LedgerConsts; | |||||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | |||||
import com.jd.blockchain.ledger.core.TransactionSet; | |||||
import com.jd.blockchain.ledger.core.UserAccountSet; | |||||
import com.jd.blockchain.ledger.BlockBody; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerDataSnapshot; | |||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.LedgerSettings; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -35,7 +30,7 @@ import com.jd.blockchain.utils.codec.Base58Utils; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
public class LedgerRepositoryImpl implements LedgerRepository { | |||||
class LedgerRepositoryImpl implements LedgerRepository { | |||||
private static final Bytes LEDGER_PREFIX = Bytes.fromString("IDX" + LedgerConsts.KEY_SEPERATOR); | private static final Bytes LEDGER_PREFIX = Bytes.fromString("IDX" + LedgerConsts.KEY_SEPERATOR); | ||||
@@ -77,8 +72,10 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
this.ledgerIndexKey = encodeLedgerIndexKey(ledgerHash); | this.ledgerIndexKey = encodeLedgerIndexKey(ledgerHash); | ||||
if (getLatestBlockHeight() < 0) { | if (getLatestBlockHeight() < 0) { | ||||
throw new LedgerException("Ledger doesn't exist!"); | |||||
throw new RuntimeException("Ledger doesn't exist!"); | |||||
} | } | ||||
retrieveLatestState(); | |||||
} | } | ||||
/* | /* | ||||
@@ -109,25 +106,27 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
@Override | @Override | ||||
public LedgerBlock getLatestBlock() { | public LedgerBlock getLatestBlock() { | ||||
LedgerState state = getLatestState(); | |||||
return state.block; | |||||
return latestState.block; | |||||
} | } | ||||
private LedgerState getLatestState() { | |||||
LedgerState state = latestState; | |||||
if (state == null) { | |||||
LedgerBlock latestBlock = innerGetBlock(innerGetLatestBlockHeight()); | |||||
state = new LedgerState(latestBlock); | |||||
latestState = state; | |||||
} | |||||
return state; | |||||
/** | |||||
* 重新检索加载最新的状态; | |||||
* | |||||
* @return | |||||
*/ | |||||
private LedgerState retrieveLatestState() { | |||||
LedgerBlock latestBlock = innerGetBlock(innerGetLatestBlockHeight()); | |||||
LedgerDataset ledgerDataset = innerGetLedgerDataset(latestBlock); | |||||
TransactionSet txSet = loadTransactionSet(latestBlock.getTransactionSetHash(), | |||||
ledgerDataset.getAdminDataset().getSettings().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
this.latestState = new LedgerState(latestBlock, ledgerDataset, txSet); | |||||
return latestState; | |||||
} | } | ||||
@Override | @Override | ||||
public LedgerBlock retrieveLatestBlock() { | public LedgerBlock retrieveLatestBlock() { | ||||
LedgerBlock latestBlock = innerGetBlock(innerGetLatestBlockHeight()); | |||||
latestState = new LedgerState(latestBlock); | |||||
return latestBlock; | |||||
return retrieveLatestState().block; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -186,7 +185,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
if (height < 0) { | if (height < 0) { | ||||
return null; | return null; | ||||
} | } | ||||
return innerGetBlock(getBlockHash(height)); | |||||
return innerGetBlock(innerGetBlockHash(height)); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -205,36 +204,27 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
LedgerBlockData block = new LedgerBlockData(deserialize(blockBytes)); | LedgerBlockData block = new LedgerBlockData(deserialize(blockBytes)); | ||||
if (!blockHash.equals(block.getHash())) { | if (!blockHash.equals(block.getHash())) { | ||||
throw new LedgerException("Block hash not equals to it's storage key!"); | |||||
} | |||||
// verify hash; | |||||
// boolean requiredVerifyHash = | |||||
// adminAccount.getMetadata().getSetting().getCryptoSetting().getAutoVerifyHash(); | |||||
// TODO: 未实现从配置中加载是否校验 Hash 的设置; | |||||
boolean requiredVerifyHash = false; | |||||
if (requiredVerifyHash) { | |||||
byte[] blockBodyBytes = null; | |||||
if (block.getHeight() == 0) { | |||||
// 计算创世区块的 hash 时,不包括 ledgerHash 字段; | |||||
block.setLedgerHash(null); | |||||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||||
// 恢复; | |||||
block.setLedgerHash(block.getHash()); | |||||
} else { | |||||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||||
} | |||||
HashFunction hashFunc = Crypto.getHashFunction(blockHash.getAlgorithm()); | |||||
boolean pass = hashFunc.verify(blockHash, blockBodyBytes); | |||||
if (!pass) { | |||||
throw new LedgerException("Block hash verification fail!"); | |||||
} | |||||
throw new RuntimeException("Block hash not equals to it's storage key!"); | |||||
} | |||||
// verify block hash; | |||||
byte[] blockBodyBytes = null; | |||||
if (block.getHeight() == 0) { | |||||
// 计算创世区块的 hash 时,不包括 ledgerHash 字段; | |||||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||||
} else { | |||||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||||
} | |||||
HashFunction hashFunc = Crypto.getHashFunction(blockHash.getAlgorithm()); | |||||
boolean pass = hashFunc.verify(blockHash, blockBodyBytes); | |||||
if (!pass) { | |||||
throw new RuntimeException("Block hash verification fail!"); | |||||
} | } | ||||
// verify height; | // verify height; | ||||
HashDigest indexedHash = getBlockHash(block.getHeight()); | HashDigest indexedHash = getBlockHash(block.getHeight()); | ||||
if (indexedHash == null || !indexedHash.equals(blockHash)) { | if (indexedHash == null || !indexedHash.equals(blockHash)) { | ||||
throw new LedgerException( | |||||
throw new RuntimeException( | |||||
"Illegal ledger state in storage that ledger height index doesn't match it's block data in height[" | "Illegal ledger state in storage that ledger height index doesn't match it's block data in height[" | ||||
+ block.getHeight() + "] and block hash[" + Base58Utils.encode(blockHash.toBytes()) | + block.getHeight() + "] and block hash[" + Base58Utils.encode(blockHash.toBytes()) | ||||
+ "] !"); | + "] !"); | ||||
@@ -243,9 +233,18 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
return block; | return block; | ||||
} | } | ||||
/** | |||||
* 获取最新区块的账本参数; | |||||
* | |||||
* @return | |||||
*/ | |||||
private LedgerSettings getLatestSettings() { | |||||
return getAdminInfo().getSettings(); | |||||
} | |||||
@Override | @Override | ||||
public LedgerAdministration getAdminInfo() { | |||||
return getAdminAccount(getLatestBlock()); | |||||
public LedgerAdminInfo getAdminInfo() { | |||||
return getAdminInfo(getLatestBlock()); | |||||
} | } | ||||
private LedgerBlock deserialize(byte[] blockBytes) { | private LedgerBlock deserialize(byte[] blockBytes) { | ||||
@@ -255,155 +254,110 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
@Override | @Override | ||||
public TransactionSet getTransactionSet(LedgerBlock block) { | public TransactionSet getTransactionSet(LedgerBlock block) { | ||||
long height = getLatestBlockHeight(); | long height = getLatestBlockHeight(); | ||||
TransactionSet transactionSet = null; | |||||
if (height == block.getHeight()) { | if (height == block.getHeight()) { | ||||
// 缓存读; | |||||
LedgerState state = getLatestState(); | |||||
transactionSet = state.transactionSet; | |||||
if (transactionSet == null) { | |||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
transactionSet = loadTransactionSet(block.getTransactionSetHash(), | |||||
adminAccount.getMetadata().getSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
state.transactionSet = transactionSet; | |||||
} | |||||
return transactionSet; | |||||
// 从缓存中返回最新区块的数据集; | |||||
return latestState.getTransactionSet(); | |||||
} | } | ||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
LedgerAdminInfo adminAccount = getAdminInfo(block); | |||||
// All of existing block is readonly; | // All of existing block is readonly; | ||||
return loadTransactionSet(block.getTransactionSetHash(), | |||||
adminAccount.getMetadata().getSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
return loadTransactionSet(block.getTransactionSetHash(), adminAccount.getSettings().getCryptoSetting(), | |||||
keyPrefix, exPolicyStorage, versioningStorage, true); | |||||
} | } | ||||
@Override | @Override | ||||
public LedgerAdminAccount getAdminAccount(LedgerBlock block) { | |||||
public LedgerAdminDataset getAdminInfo(LedgerBlock block) { | |||||
long height = getLatestBlockHeight(); | long height = getLatestBlockHeight(); | ||||
LedgerAdminAccount adminAccount = null; | |||||
if (height == block.getHeight()) { | if (height == block.getHeight()) { | ||||
// 缓存读; | |||||
LedgerState state = getLatestState(); | |||||
adminAccount = state.adminAccount; | |||||
if (adminAccount == null) { | |||||
adminAccount = new LedgerAdminAccount(block.getAdminAccountHash(), keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
state.adminAccount = adminAccount; | |||||
} | |||||
return adminAccount; | |||||
return latestState.getAdminDataset(); | |||||
} | } | ||||
return new LedgerAdminAccount(block.getAdminAccountHash(), keyPrefix, exPolicyStorage, versioningStorage, true); | |||||
return createAdminDataset(block); | |||||
} | |||||
private LedgerAdminDataset createAdminDataset(LedgerBlock block) { | |||||
return new LedgerAdminDataset(block.getAdminAccountHash(), keyPrefix, exPolicyStorage, versioningStorage, true); | |||||
} | } | ||||
@Override | @Override | ||||
public UserAccountSet getUserAccountSet(LedgerBlock block) { | |||||
public UserAccountQuery getUserAccountSet(LedgerBlock block) { | |||||
long height = getLatestBlockHeight(); | long height = getLatestBlockHeight(); | ||||
UserAccountSet userAccountSet = null; | |||||
if (height == block.getHeight()) { | if (height == block.getHeight()) { | ||||
// 缓存读; | |||||
LedgerState state = getLatestState(); | |||||
userAccountSet = state.userAccountSet; | |||||
if (userAccountSet == null) { | |||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
userAccountSet = loadUserAccountSet(block.getUserAccountSetHash(), | |||||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
state.userAccountSet = userAccountSet; | |||||
} | |||||
return userAccountSet; | |||||
return latestState.getUserAccountSet(); | |||||
} | } | ||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
return loadUserAccountSet(block.getUserAccountSetHash(), adminAccount.getPreviousSetting().getCryptoSetting(), | |||||
keyPrefix, exPolicyStorage, versioningStorage, true); | |||||
LedgerAdminDataset adminAccount = getAdminInfo(block); | |||||
return createUserAccountSet(block, adminAccount.getSettings().getCryptoSetting()); | |||||
} | |||||
private UserAccountSet createUserAccountSet(LedgerBlock block, CryptoSetting cryptoSetting) { | |||||
return loadUserAccountSet(block.getUserAccountSetHash(), cryptoSetting, keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
} | } | ||||
@Override | @Override | ||||
public DataAccountSet getDataAccountSet(LedgerBlock block) { | |||||
public DataAccountQuery getDataAccountSet(LedgerBlock block) { | |||||
long height = getLatestBlockHeight(); | long height = getLatestBlockHeight(); | ||||
DataAccountSet dataAccountSet = null; | |||||
if (height == block.getHeight()) { | if (height == block.getHeight()) { | ||||
// 缓存读; | |||||
LedgerState state = getLatestState(); | |||||
dataAccountSet = state.dataAccountSet; | |||||
if (dataAccountSet == null) { | |||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
dataAccountSet = loadDataAccountSet(block.getDataAccountSetHash(), | |||||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
state.dataAccountSet = dataAccountSet; | |||||
} | |||||
return dataAccountSet; | |||||
return latestState.getDataAccountSet(); | |||||
} | } | ||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
return loadDataAccountSet(block.getDataAccountSetHash(), adminAccount.getPreviousSetting().getCryptoSetting(), | |||||
keyPrefix, exPolicyStorage, versioningStorage, true); | |||||
LedgerAdminDataset adminAccount = getAdminInfo(block); | |||||
return createDataAccountSet(block, adminAccount.getSettings().getCryptoSetting()); | |||||
} | |||||
private DataAccountSet createDataAccountSet(LedgerBlock block, CryptoSetting setting) { | |||||
return loadDataAccountSet(block.getDataAccountSetHash(), setting, keyPrefix, exPolicyStorage, versioningStorage, | |||||
true); | |||||
} | } | ||||
@Override | @Override | ||||
public ContractAccountSet getContractAccountSet(LedgerBlock block) { | |||||
public ContractAccountQuery getContractAccountSet(LedgerBlock block) { | |||||
long height = getLatestBlockHeight(); | long height = getLatestBlockHeight(); | ||||
ContractAccountSet contractAccountSet = null; | |||||
if (height == block.getHeight()) { | if (height == block.getHeight()) { | ||||
// 缓存读; | |||||
LedgerState state = getLatestState(); | |||||
contractAccountSet = state.contractAccountSet; | |||||
if (contractAccountSet == null) { | |||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
contractAccountSet = loadContractAccountSet(block.getContractAccountSetHash(), | |||||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
state.contractAccountSet = contractAccountSet; | |||||
} | |||||
return contractAccountSet; | |||||
return latestState.getContractAccountSet(); | |||||
} | } | ||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
return loadContractAccountSet(block.getContractAccountSetHash(), | |||||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, versioningStorage, | |||||
true); | |||||
LedgerAdminDataset adminAccount = getAdminInfo(block); | |||||
return createContractAccountSet(block, adminAccount.getSettings().getCryptoSetting()); | |||||
} | |||||
private ContractAccountSet createContractAccountSet(LedgerBlock block, CryptoSetting cryptoSetting) { | |||||
return loadContractAccountSet(block.getContractAccountSetHash(), cryptoSetting, keyPrefix, exPolicyStorage, | |||||
versioningStorage, true); | |||||
} | } | ||||
@Override | @Override | ||||
public LedgerDataSet getDataSet(LedgerBlock block) { | |||||
public LedgerDataset getDataSet(LedgerBlock block) { | |||||
long height = getLatestBlockHeight(); | long height = getLatestBlockHeight(); | ||||
LedgerDataSet ledgerDataSet = null; | |||||
if (height == block.getHeight()) { | if (height == block.getHeight()) { | ||||
// 缓存读; | |||||
LedgerState state = getLatestState(); | |||||
ledgerDataSet = state.ledgerDataSet; | |||||
if (ledgerDataSet == null) { | |||||
ledgerDataSet = innerDataSet(block); | |||||
state.ledgerDataSet = ledgerDataSet; | |||||
} | |||||
return ledgerDataSet; | |||||
return latestState.getLedgerDataset(); | |||||
} | } | ||||
// All of existing block is readonly; | // All of existing block is readonly; | ||||
return innerDataSet(block); | |||||
return innerGetLedgerDataset(block); | |||||
} | } | ||||
private LedgerDataSet innerDataSet(LedgerBlock block) { | |||||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||||
UserAccountSet userAccountSet = getUserAccountSet(block); | |||||
DataAccountSet dataAccountSet = getDataAccountSet(block); | |||||
ContractAccountSet contractAccountSet = getContractAccountSet(block); | |||||
return new LedgerDataSetImpl(adminAccount, userAccountSet, dataAccountSet, contractAccountSet, true); | |||||
private LedgerDataset innerGetLedgerDataset(LedgerBlock block) { | |||||
LedgerAdminDataset adminDataset = createAdminDataset(block); | |||||
CryptoSetting cryptoSetting = adminDataset.getSettings().getCryptoSetting(); | |||||
UserAccountSet userAccountSet = createUserAccountSet(block, cryptoSetting); | |||||
DataAccountSet dataAccountSet = createDataAccountSet(block, cryptoSetting); | |||||
ContractAccountSet contractAccountSet = createContractAccountSet(block, cryptoSetting); | |||||
return new LedgerDataset(adminDataset, userAccountSet, dataAccountSet, contractAccountSet, true); | |||||
} | } | ||||
@Override | @Override | ||||
public synchronized LedgerEditor createNextBlock() { | public synchronized LedgerEditor createNextBlock() { | ||||
if (closed) { | if (closed) { | ||||
throw new LedgerException("Ledger repository has been closed!"); | |||||
throw new RuntimeException("Ledger repository has been closed!"); | |||||
} | } | ||||
if (this.nextBlockEditor != null) { | if (this.nextBlockEditor != null) { | ||||
throw new LedgerException( | |||||
throw new RuntimeException( | |||||
"A new block is in process, cann't create another one until it finish by committing or canceling."); | "A new block is in process, cann't create another one until it finish by committing or canceling."); | ||||
} | } | ||||
LedgerBlock previousBlock = getLatestBlock(); | LedgerBlock previousBlock = getLatestBlock(); | ||||
LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor( | |||||
getAdminInfo().getMetadata().getSetting(), previousBlock, keyPrefix, exPolicyStorage, | |||||
versioningStorage); | |||||
LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(previousBlock, getLatestSettings(), | |||||
keyPrefix, exPolicyStorage, versioningStorage); | |||||
NewBlockCommittingMonitor committingMonitor = new NewBlockCommittingMonitor(editor, this); | NewBlockCommittingMonitor committingMonitor = new NewBlockCommittingMonitor(editor, this); | ||||
this.nextBlockEditor = committingMonitor; | this.nextBlockEditor = committingMonitor; | ||||
return committingMonitor; | return committingMonitor; | ||||
@@ -420,70 +374,45 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
return; | return; | ||||
} | } | ||||
if (this.nextBlockEditor != null) { | if (this.nextBlockEditor != null) { | ||||
throw new LedgerException("A new block is in process, cann't close the ledger repository!"); | |||||
throw new RuntimeException("A new block is in process, cann't close the ledger repository!"); | |||||
} | } | ||||
closed = true; | closed = true; | ||||
} | } | ||||
static Bytes encodeLedgerIndexKey(HashDigest ledgerHash) { | static Bytes encodeLedgerIndexKey(HashDigest ledgerHash) { | ||||
// return LEDGER_PREFIX + Base58Utils.encode(ledgerHash.toBytes()); | |||||
// return new Bytes(ledgerHash.toBytes()).concatTo(LEDGER_PREFIX); | |||||
return LEDGER_PREFIX.concat(ledgerHash); | return LEDGER_PREFIX.concat(ledgerHash); | ||||
} | } | ||||
static Bytes encodeBlockStorageKey(HashDigest blockHash) { | static Bytes encodeBlockStorageKey(HashDigest blockHash) { | ||||
// String key = ByteArray.toBase58(blockHash.toBytes()); | |||||
// return BLOCK_PREFIX + key; | |||||
return BLOCK_PREFIX.concat(blockHash); | return BLOCK_PREFIX.concat(blockHash); | ||||
} | } | ||||
static LedgerDataSetImpl newDataSet(LedgerInitSetting initSetting, String keyPrefix, | |||||
static LedgerDataset newDataSet(LedgerInitSetting initSetting, String keyPrefix, | |||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | ||||
LedgerAdminAccount adminAccount = new LedgerAdminAccount(initSetting, keyPrefix, ledgerExStorage, | |||||
LedgerAdminDataset adminAccount = new LedgerAdminDataset(initSetting, keyPrefix, ledgerExStorage, | |||||
ledgerVerStorage); | ledgerVerStorage); | ||||
String usersetKeyPrefix = keyPrefix + USER_SET_PREFIX; | String usersetKeyPrefix = keyPrefix + USER_SET_PREFIX; | ||||
String datasetKeyPrefix = keyPrefix + DATA_SET_PREFIX; | String datasetKeyPrefix = keyPrefix + DATA_SET_PREFIX; | ||||
String contractsetKeyPrefix = keyPrefix + CONTRACT_SET_PREFIX; | String contractsetKeyPrefix = keyPrefix + CONTRACT_SET_PREFIX; | ||||
// String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | |||||
// UserAccountSet userAccountSet = new | |||||
// UserAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerExStorage), | |||||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerVerStorage), | |||||
// DEFAULT_ACCESS_POLICY); | |||||
UserAccountSet userAccountSet = new UserAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||||
UserAccountSet userAccountSet = new UserAccountSet(adminAccount.getSettings().getCryptoSetting(), | |||||
usersetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | usersetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | ||||
// DataAccountSet dataAccountSet = new | |||||
// DataAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerExStorage), | |||||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerVerStorage), | |||||
// DEFAULT_ACCESS_POLICY); | |||||
DataAccountSet dataAccountSet = new DataAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||||
DataAccountSet dataAccountSet = new DataAccountSet(adminAccount.getSettings().getCryptoSetting(), | |||||
datasetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | datasetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | ||||
// ContractAccountSet contractAccountSet = new | |||||
// ContractAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerExStorage), | |||||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerVerStorage), | |||||
// DEFAULT_ACCESS_POLICY); | |||||
ContractAccountSet contractAccountSet = new ContractAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||||
ContractAccountSet contractAccountSet = new ContractAccountSet(adminAccount.getSettings().getCryptoSetting(), | |||||
contractsetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | contractsetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | ||||
LedgerDataSetImpl newDataSet = new LedgerDataSetImpl(adminAccount, userAccountSet, dataAccountSet, | |||||
LedgerDataset newDataSet = new LedgerDataset(adminAccount, userAccountSet, dataAccountSet, | |||||
contractAccountSet, false); | contractAccountSet, false); | ||||
return newDataSet; | return newDataSet; | ||||
} | } | ||||
static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix, | |||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
// TransactionSet transactionSet = new | |||||
// TransactionSet(ledgerSetting.getCryptoSetting(), | |||||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), | |||||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerVerStorage)); | |||||
static TransactionSet newTransactionSet(LedgerSettings ledgerSetting, String keyPrefix, | |||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | ||||
@@ -492,13 +421,11 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
return transactionSet; | return transactionSet; | ||||
} | } | ||||
static LedgerDataSetImpl loadDataSet(LedgerDataSnapshot dataSnapshot, String keyPrefix, | |||||
static LedgerDataset loadDataSet(LedgerDataSnapshot dataSnapshot, CryptoSetting cryptoSetting, String keyPrefix, | |||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, boolean readonly) { | ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, boolean readonly) { | ||||
LedgerAdminAccount adminAccount = new LedgerAdminAccount(dataSnapshot.getAdminAccountHash(), keyPrefix, | |||||
LedgerAdminDataset adminAccount = new LedgerAdminDataset(dataSnapshot.getAdminAccountHash(), keyPrefix, | |||||
ledgerExStorage, ledgerVerStorage, readonly); | ledgerExStorage, ledgerVerStorage, readonly); | ||||
CryptoSetting cryptoSetting = adminAccount.getPreviousSetting().getCryptoSetting(); | |||||
UserAccountSet userAccountSet = loadUserAccountSet(dataSnapshot.getUserAccountSetHash(), cryptoSetting, | UserAccountSet userAccountSet = loadUserAccountSet(dataSnapshot.getUserAccountSetHash(), cryptoSetting, | ||||
keyPrefix, ledgerExStorage, ledgerVerStorage, readonly); | keyPrefix, ledgerExStorage, ledgerVerStorage, readonly); | ||||
@@ -508,7 +435,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
ContractAccountSet contractAccountSet = loadContractAccountSet(dataSnapshot.getContractAccountSetHash(), | ContractAccountSet contractAccountSet = loadContractAccountSet(dataSnapshot.getContractAccountSetHash(), | ||||
cryptoSetting, keyPrefix, ledgerExStorage, ledgerVerStorage, readonly); | cryptoSetting, keyPrefix, ledgerExStorage, ledgerVerStorage, readonly); | ||||
LedgerDataSetImpl dataset = new LedgerDataSetImpl(adminAccount, userAccountSet, dataAccountSet, | |||||
LedgerDataset dataset = new LedgerDataset(adminAccount, userAccountSet, dataAccountSet, | |||||
contractAccountSet, readonly); | contractAccountSet, readonly); | ||||
return dataset; | return dataset; | ||||
@@ -517,10 +444,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
static UserAccountSet loadUserAccountSet(HashDigest userAccountSetHash, CryptoSetting cryptoSetting, | static UserAccountSet loadUserAccountSet(HashDigest userAccountSetHash, CryptoSetting cryptoSetting, | ||||
String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | ||||
boolean readonly) { | boolean readonly) { | ||||
// return new UserAccountSet(userAccountSetHash, cryptoSetting, | |||||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerExStorage), | |||||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerVerStorage), readonly, | |||||
// DEFAULT_ACCESS_POLICY); | |||||
String usersetKeyPrefix = keyPrefix + USER_SET_PREFIX; | String usersetKeyPrefix = keyPrefix + USER_SET_PREFIX; | ||||
return new UserAccountSet(userAccountSetHash, cryptoSetting, usersetKeyPrefix, ledgerExStorage, | return new UserAccountSet(userAccountSetHash, cryptoSetting, usersetKeyPrefix, ledgerExStorage, | ||||
@@ -530,10 +453,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
static DataAccountSet loadDataAccountSet(HashDigest dataAccountSetHash, CryptoSetting cryptoSetting, | static DataAccountSet loadDataAccountSet(HashDigest dataAccountSetHash, CryptoSetting cryptoSetting, | ||||
String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | ||||
boolean readonly) { | boolean readonly) { | ||||
// return new DataAccountSet(dataAccountSetHash, cryptoSetting, | |||||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerExStorage, | |||||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerVerStorage), readonly, | |||||
// DEFAULT_ACCESS_POLICY); | |||||
String datasetKeyPrefix = keyPrefix + DATA_SET_PREFIX; | String datasetKeyPrefix = keyPrefix + DATA_SET_PREFIX; | ||||
return new DataAccountSet(dataAccountSetHash, cryptoSetting, datasetKeyPrefix, ledgerExStorage, | return new DataAccountSet(dataAccountSetHash, cryptoSetting, datasetKeyPrefix, ledgerExStorage, | ||||
@@ -543,10 +462,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
static ContractAccountSet loadContractAccountSet(HashDigest contractAccountSetHash, CryptoSetting cryptoSetting, | static ContractAccountSet loadContractAccountSet(HashDigest contractAccountSetHash, CryptoSetting cryptoSetting, | ||||
String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | ||||
boolean readonly) { | boolean readonly) { | ||||
// return new ContractAccountSet(contractAccountSetHash, cryptoSetting, | |||||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerExStorage, | |||||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerVerStorage), readonly, | |||||
// DEFAULT_ACCESS_POLICY); | |||||
String contractsetKeyPrefix = keyPrefix + CONTRACT_SET_PREFIX; | String contractsetKeyPrefix = keyPrefix + CONTRACT_SET_PREFIX; | ||||
return new ContractAccountSet(contractAccountSetHash, cryptoSetting, contractsetKeyPrefix, ledgerExStorage, | return new ContractAccountSet(contractAccountSetHash, cryptoSetting, contractsetKeyPrefix, ledgerExStorage, | ||||
@@ -555,9 +470,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
static TransactionSet loadTransactionSet(HashDigest txsetHash, CryptoSetting cryptoSetting, String keyPrefix, | static TransactionSet loadTransactionSet(HashDigest txsetHash, CryptoSetting cryptoSetting, String keyPrefix, | ||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, boolean readonly) { | ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, boolean readonly) { | ||||
// return new TransactionSet(txsetHash, cryptoSetting, | |||||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), | |||||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerVerStorage), readonly); | |||||
String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | ||||
return new TransactionSet(txsetHash, cryptoSetting, txsetKeyPrefix, ledgerExStorage, ledgerVerStorage, | return new TransactionSet(txsetHash, cryptoSetting, txsetKeyPrefix, ledgerExStorage, ledgerVerStorage, | ||||
@@ -576,6 +488,26 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
this.ledgerRepo = ledgerRepo; | this.ledgerRepo = ledgerRepo; | ||||
} | } | ||||
@Override | |||||
public HashDigest getLedgerHash() { | |||||
return editor.getLedgerHash(); | |||||
} | |||||
@Override | |||||
public long getBlockHeight() { | |||||
return editor.getBlockHeight(); | |||||
} | |||||
@Override | |||||
public LedgerDataset getLedgerDataset() { | |||||
return editor.getLedgerDataset(); | |||||
} | |||||
@Override | |||||
public TransactionSet getTransactionSet() { | |||||
return editor.getTransactionSet(); | |||||
} | |||||
@Override | @Override | ||||
public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | ||||
return editor.newTransaction(txRequest); | return editor.newTransaction(txRequest); | ||||
@@ -590,8 +522,9 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
public void commit() { | public void commit() { | ||||
try { | try { | ||||
editor.commit(); | editor.commit(); | ||||
LedgerBlock latestBlock = editor.getNewlyBlock(); | |||||
ledgerRepo.latestState = new LedgerState(latestBlock); | |||||
LedgerBlock latestBlock = editor.getCurrentBlock(); | |||||
ledgerRepo.latestState = new LedgerState(latestBlock, editor.getLedgerDataset(), | |||||
editor.getTransactionSet()); | |||||
} finally { | } finally { | ||||
ledgerRepo.nextBlockEditor = null; | ledgerRepo.nextBlockEditor = null; | ||||
} | } | ||||
@@ -618,20 +551,39 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||||
private final LedgerBlock block; | private final LedgerBlock block; | ||||
private volatile LedgerAdminAccount adminAccount; | |||||
private final TransactionSet transactionSet; | |||||
private volatile UserAccountSet userAccountSet; | |||||
private final LedgerDataset ledgerDataset; | |||||
private volatile DataAccountSet dataAccountSet; | |||||
public LedgerState(LedgerBlock block, LedgerDataset ledgerDataset, TransactionSet transactionSet) { | |||||
this.block = block; | |||||
this.ledgerDataset = ledgerDataset; | |||||
this.transactionSet = transactionSet; | |||||
private volatile ContractAccountSet contractAccountSet; | |||||
} | |||||
private volatile TransactionSet transactionSet; | |||||
public LedgerAdminDataset getAdminDataset() { | |||||
return ledgerDataset.getAdminDataset(); | |||||
} | |||||
private volatile LedgerDataSet ledgerDataSet; | |||||
public LedgerDataset getLedgerDataset() { | |||||
return ledgerDataset; | |||||
} | |||||
public LedgerState(LedgerBlock block) { | |||||
this.block = block; | |||||
public ContractAccountQuery getContractAccountSet() { | |||||
return ledgerDataset.getContractAccountset(); | |||||
} | |||||
public DataAccountQuery getDataAccountSet() { | |||||
return ledgerDataset.getDataAccountSet(); | |||||
} | |||||
public UserAccountQuery getUserAccountSet() { | |||||
return ledgerDataset.getUserAccountSet(); | |||||
} | |||||
public TransactionSet getTransactionSet() { | |||||
return transactionSet; | |||||
} | } | ||||
} | } |
@@ -0,0 +1,20 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.Set; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public interface LedgerSecurityManager { | |||||
String DEFAULT_ROLE = "DEFAULT"; | |||||
/** | |||||
* 创建一项与指定的终端用户和节点参与方相关的安全策略; | |||||
* | |||||
* @param endpoints 终端用户的地址列表; | |||||
* @param nodes 节点参与方的地址列表; | |||||
* @return 一项安全策略; | |||||
*/ | |||||
SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes); | |||||
} |
@@ -0,0 +1,396 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import com.jd.blockchain.ledger.LedgerPermission; | |||||
import com.jd.blockchain.ledger.LedgerSecurityException; | |||||
import com.jd.blockchain.ledger.ParticipantDataQuery; | |||||
import com.jd.blockchain.ledger.ParticipantDoesNotExistException; | |||||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||||
import com.jd.blockchain.ledger.RolePrivileges; | |||||
import com.jd.blockchain.ledger.RolesPolicy; | |||||
import com.jd.blockchain.ledger.TransactionPermission; | |||||
import com.jd.blockchain.ledger.UserDoesNotExistException; | |||||
import com.jd.blockchain.ledger.UserRoles; | |||||
import com.jd.blockchain.ledger.UserRolesSettings; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
/** | |||||
* 账本安全管理器; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public class LedgerSecurityManagerImpl implements LedgerSecurityManager { | |||||
private RolePrivilegeSettings rolePrivilegeSettings; | |||||
private UserRolesSettings userRolesSettings; | |||||
// 用户的权限配置 | |||||
private Map<Bytes, UserRolesPrivileges> userPrivilegesCache = new ConcurrentHashMap<>(); | |||||
private Map<Bytes, UserRoles> userRolesCache = new ConcurrentHashMap<>(); | |||||
private Map<String, RolePrivileges> rolesPrivilegeCache = new ConcurrentHashMap<>(); | |||||
private ParticipantDataQuery participantsQuery; | |||||
private UserAccountQuery userAccountsQuery; | |||||
public LedgerSecurityManagerImpl(RolePrivilegeSettings rolePrivilegeSettings, UserRolesSettings userRolesSettings, | |||||
ParticipantDataQuery participantsQuery, UserAccountQuery userAccountsQuery) { | |||||
this.rolePrivilegeSettings = rolePrivilegeSettings; | |||||
this.userRolesSettings = userRolesSettings; | |||||
this.participantsQuery = participantsQuery; | |||||
this.userAccountsQuery = userAccountsQuery; | |||||
} | |||||
@Override | |||||
public SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) { | |||||
Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap = new HashMap<>(); | |||||
Map<Bytes, UserRolesPrivileges> nodePrivilegeMap = new HashMap<>(); | |||||
for (Bytes userAddress : endpoints) { | |||||
UserRolesPrivileges userPrivileges = getUserRolesPrivilegs(userAddress); | |||||
endpointPrivilegeMap.put(userAddress, userPrivileges); | |||||
} | |||||
for (Bytes userAddress : nodes) { | |||||
UserRolesPrivileges userPrivileges = getUserRolesPrivilegs(userAddress); | |||||
nodePrivilegeMap.put(userAddress, userPrivileges); | |||||
} | |||||
return new UserRolesSecurityPolicy(endpointPrivilegeMap, nodePrivilegeMap, participantsQuery, userAccountsQuery); | |||||
} | |||||
private UserRolesPrivileges getUserRolesPrivilegs(Bytes userAddress) { | |||||
UserRolesPrivileges userPrivileges = userPrivilegesCache.get(userAddress); | |||||
if (userPrivileges != null) { | |||||
return userPrivileges; | |||||
} | |||||
UserRoles userRoles = null; | |||||
List<RolePrivileges> privilegesList = new ArrayList<>(); | |||||
// 加载用户的角色列表; | |||||
userRoles = userRolesCache.get(userAddress); | |||||
if (userRoles == null) { | |||||
userRoles = userRolesSettings.getUserRoles(userAddress); | |||||
if (userRoles != null) { | |||||
userRolesCache.put(userAddress, userRoles); | |||||
} | |||||
} | |||||
// 计算用户的综合权限; | |||||
if (userRoles != null) { | |||||
String[] roles = userRoles.getRoles(); | |||||
RolePrivileges privilege = null; | |||||
for (String role : roles) { | |||||
// 先从缓存读取,如果没有再从原始数据源进行加载; | |||||
privilege = rolesPrivilegeCache.get(role); | |||||
if (privilege == null) { | |||||
privilege = rolePrivilegeSettings.getRolePrivilege(role); | |||||
if (privilege == null) { | |||||
// 略过不存在的无效角色; | |||||
continue; | |||||
} | |||||
rolesPrivilegeCache.put(role, privilege); | |||||
} | |||||
privilegesList.add(privilege); | |||||
} | |||||
} | |||||
// 如果用户未被授权任何角色,则采用默认角色的权限; | |||||
if (privilegesList.size() == 0) { | |||||
RolePrivileges privilege = getDefaultRolePrivilege(); | |||||
privilegesList.add(privilege); | |||||
} | |||||
if (userRoles == null) { | |||||
userPrivileges = new UserRolesPrivileges(userAddress, RolesPolicy.UNION, privilegesList); | |||||
} else { | |||||
userPrivileges = new UserRolesPrivileges(userAddress, userRoles.getPolicy(), privilegesList); | |||||
} | |||||
userPrivilegesCache.put(userAddress, userPrivileges); | |||||
return userPrivileges; | |||||
} | |||||
private RolePrivileges getDefaultRolePrivilege() { | |||||
RolePrivileges privileges = rolesPrivilegeCache.get(DEFAULT_ROLE); | |||||
if (privileges == null) { | |||||
privileges = rolePrivilegeSettings.getRolePrivilege(DEFAULT_ROLE); | |||||
if (privileges == null) { | |||||
throw new LedgerSecurityException( | |||||
"This ledger is missing the default role-privilege settings for the users who don't have a role!"); | |||||
} | |||||
} | |||||
return privileges; | |||||
} | |||||
private class UserRolesSecurityPolicy implements SecurityPolicy { | |||||
/** | |||||
* 终端用户的权限表; | |||||
*/ | |||||
private Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap = new HashMap<>(); | |||||
/** | |||||
* 节点参与方的权限表; | |||||
*/ | |||||
private Map<Bytes, UserRolesPrivileges> nodePrivilegeMap = new HashMap<>(); | |||||
private ParticipantDataQuery participantsQuery; | |||||
private UserAccountQuery userAccountsQuery; | |||||
public UserRolesSecurityPolicy(Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap, | |||||
Map<Bytes, UserRolesPrivileges> nodePrivilegeMap, ParticipantDataQuery participantsQuery, | |||||
UserAccountQuery userAccountsQuery) { | |||||
this.endpointPrivilegeMap = endpointPrivilegeMap; | |||||
this.nodePrivilegeMap = nodePrivilegeMap; | |||||
this.participantsQuery = participantsQuery; | |||||
this.userAccountsQuery = userAccountsQuery; | |||||
} | |||||
@Override | |||||
public boolean isEndpointEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||||
if (p.getLedgerPrivileges().isEnable(permission)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||||
if (!p.getLedgerPrivileges().isEnable(permission)) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isEndpointEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||||
if (p.getTransactionPrivileges().isEnable(permission)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||||
if (!p.getTransactionPrivileges().isEnable(permission)) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isNodeEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||||
if (p.getLedgerPrivileges().isEnable(permission)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||||
if (!p.getLedgerPrivileges().isEnable(permission)) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isNodeEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||||
if (p.getTransactionPrivileges().isEnable(permission)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||||
if (!p.getTransactionPrivileges().isEnable(permission)) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
@Override | |||||
public void checkEndpointPermission(LedgerPermission permission, MultiIDsPolicy midPolicy) | |||||
throws LedgerSecurityException { | |||||
if (!isEndpointEnable(permission, midPolicy)) { | |||||
throw new LedgerSecurityException(String.format( | |||||
"The security policy [Permission=%s, Policy=%s] for endpoints rejected the current operation!", | |||||
permission, midPolicy)); | |||||
} | |||||
} | |||||
@Override | |||||
public void checkEndpointPermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||||
throws LedgerSecurityException { | |||||
if (!isEndpointEnable(permission, midPolicy)) { | |||||
throw new LedgerSecurityException(String.format( | |||||
"The security policy [Permission=%s, Policy=%s] for endpoints rejected the current operation!", | |||||
permission, midPolicy)); | |||||
} | |||||
} | |||||
@Override | |||||
public void checkNodePermission(LedgerPermission permission, MultiIDsPolicy midPolicy) | |||||
throws LedgerSecurityException { | |||||
if (!isNodeEnable(permission, midPolicy)) { | |||||
throw new LedgerSecurityException(String.format( | |||||
"The security policy [Permission=%s, Policy=%s] for nodes rejected the current operation!", | |||||
permission, midPolicy)); | |||||
} | |||||
} | |||||
@Override | |||||
public void checkNodePermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||||
throws LedgerSecurityException { | |||||
if (!isNodeEnable(permission, midPolicy)) { | |||||
throw new LedgerSecurityException(String.format( | |||||
"The security policy [Permission=%s, Policy=%s] for nodes rejected the current operation!", | |||||
permission, midPolicy)); | |||||
} | |||||
} | |||||
@Override | |||||
public Set<Bytes> getEndpoints() { | |||||
return endpointPrivilegeMap.keySet(); | |||||
} | |||||
@Override | |||||
public Set<Bytes> getNodes() { | |||||
return nodePrivilegeMap.keySet(); | |||||
} | |||||
@Override | |||||
public boolean isEndpointValid(MultiIDsPolicy midPolicy) { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (Bytes address : getEndpoints()) { | |||||
if (userAccountsQuery.contains(address)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (Bytes address : getEndpoints()) { | |||||
if (!userAccountsQuery.contains(address)) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isNodeValid(MultiIDsPolicy midPolicy) { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (Bytes address : getNodes()) { | |||||
if (participantsQuery.contains(address)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (Bytes address : getNodes()) { | |||||
if (!participantsQuery.contains(address)) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
@Override | |||||
public void checkEndpointValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (Bytes address : getEndpoints()) { | |||||
if (userAccountsQuery.contains(address)) { | |||||
return; | |||||
} | |||||
} | |||||
throw new UserDoesNotExistException("All endpoint signers were not registered!"); | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (Bytes address : getEndpoints()) { | |||||
if (!userAccountsQuery.contains(address)) { | |||||
throw new UserDoesNotExistException("The endpoint signer[" + address + "] was not registered!"); | |||||
} | |||||
} | |||||
return; | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
@Override | |||||
public void checkNodeValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||||
// 至少一个; | |||||
for (Bytes address : getNodes()) { | |||||
if (participantsQuery.contains(address)) { | |||||
return; | |||||
} | |||||
} | |||||
throw new ParticipantDoesNotExistException("All node signers were not registered as participant!"); | |||||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||||
// 全部; | |||||
for (Bytes address : getNodes()) { | |||||
if (!participantsQuery.contains(address)) { | |||||
throw new ParticipantDoesNotExistException( | |||||
"The node signer[" + address + "] was not registered as participant!"); | |||||
} | |||||
} | |||||
} else { | |||||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -13,18 +13,25 @@ import java.util.List; | |||||
public interface LedgerTransactionContext { | public interface LedgerTransactionContext { | ||||
/** | /** | ||||
* 账本数据; | |||||
* 账本数据集合; | |||||
* | * | ||||
* @return | * @return | ||||
*/ | */ | ||||
LedgerDataSet getDataSet(); | |||||
LedgerDataset getDataset(); | |||||
/** | |||||
* 事务集合; | |||||
* | |||||
* @return | |||||
*/ | |||||
TransactionSet getTransactionSet(); | |||||
/** | /** | ||||
* 交易请求; | * 交易请求; | ||||
* | * | ||||
* @return | * @return | ||||
*/ | */ | ||||
TransactionRequest getRequestTX(); | |||||
TransactionRequest getTransactionRequest(); | |||||
/** | /** | ||||
* 提交对账本数据的修改,以指定的交易状态提交交易; | * 提交对账本数据的修改,以指定的交易状态提交交易; | ||||
@@ -1,7 +1,4 @@ | |||||
package com.jd.blockchain.ledger.core.impl; | |||||
import java.util.Arrays; | |||||
import java.util.Comparator; | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.DigitalSignature; | import com.jd.blockchain.ledger.DigitalSignature; | ||||
@@ -29,48 +26,27 @@ public class LedgerTransactionData implements LedgerTransaction { | |||||
private OperationResult[] operationResults; | private OperationResult[] operationResults; | ||||
// private HashDigest adminAccountHash; | |||||
// | |||||
// private HashDigest userAccountSetHash; | |||||
// | |||||
// private HashDigest dataAccountSetHash; | |||||
// | |||||
// private HashDigest contractAccountSetHash; | |||||
/** | /** | ||||
* Declare a private no-arguments constructor for deserializing purpose; | * Declare a private no-arguments constructor for deserializing purpose; | ||||
*/ | */ | ||||
@SuppressWarnings("unused") | |||||
private LedgerTransactionData() { | private LedgerTransactionData() { | ||||
// this.txSnapshot = new TransactionStagedSnapshot(); | |||||
} | } | ||||
/** | /** | ||||
* @param blockHeight | |||||
* 区块链高度; | |||||
* @param txReq | |||||
* 交易请求; | |||||
* @param execState | |||||
* 执行状态; | |||||
* @param txSnapshot | |||||
* 交易级的系统快照; | |||||
* @param blockHeight 区块链高度; | |||||
* @param txReq 交易请求; | |||||
* @param execState 执行状态; | |||||
* @param txSnapshot 交易级的系统快照; | |||||
*/ | */ | ||||
public LedgerTransactionData(long blockHeight, TransactionRequest txReq, TransactionState execState, | public LedgerTransactionData(long blockHeight, TransactionRequest txReq, TransactionState execState, | ||||
TransactionStagedSnapshot txSnapshot, OperationResult... opResults) { | TransactionStagedSnapshot txSnapshot, OperationResult... opResults) { | ||||
this.blockHeight = blockHeight; | this.blockHeight = blockHeight; | ||||
// this.txSnapshot = txSnapshot == null ? new TransactionStagedSnapshot() : txSnapshot; | |||||
this.txSnapshot = txSnapshot; | this.txSnapshot = txSnapshot; | ||||
this.transactionContent = txReq.getTransactionContent(); | this.transactionContent = txReq.getTransactionContent(); | ||||
this.endpointSignatures = txReq.getEndpointSignatures(); | this.endpointSignatures = txReq.getEndpointSignatures(); | ||||
this.nodeSignatures = txReq.getNodeSignatures(); | this.nodeSignatures = txReq.getNodeSignatures(); | ||||
this.executionState = execState; | this.executionState = execState; | ||||
if (opResults != null) { | |||||
Arrays.sort(opResults, new Comparator<OperationResult>() { | |||||
@Override | |||||
public int compare(OperationResult o1, OperationResult o2) { | |||||
return o1.getIndex() - o2.getIndex(); | |||||
} | |||||
}); | |||||
} | |||||
this.operationResults = opResults; | this.operationResults = opResults; | ||||
} | } | ||||
@@ -116,17 +92,17 @@ public class LedgerTransactionData implements LedgerTransaction { | |||||
@Override | @Override | ||||
public HashDigest getUserAccountSetHash() { | public HashDigest getUserAccountSetHash() { | ||||
return txSnapshot == null ? null :txSnapshot.getUserAccountSetHash(); | |||||
return txSnapshot == null ? null : txSnapshot.getUserAccountSetHash(); | |||||
} | } | ||||
@Override | @Override | ||||
public HashDigest getDataAccountSetHash() { | public HashDigest getDataAccountSetHash() { | ||||
return txSnapshot == null ? null :txSnapshot.getDataAccountSetHash(); | |||||
return txSnapshot == null ? null : txSnapshot.getDataAccountSetHash(); | |||||
} | } | ||||
@Override | @Override | ||||
public HashDigest getContractAccountSetHash() { | public HashDigest getContractAccountSetHash() { | ||||
return txSnapshot == null ? null :txSnapshot.getContractAccountSetHash(); | |||||
return txSnapshot == null ? null : txSnapshot.getContractAccountSetHash(); | |||||
} | } | ||||
public void setTxSnapshot(TransactionStagedSnapshot txSnapshot) { | public void setTxSnapshot(TransactionStagedSnapshot txSnapshot) { | ||||
@@ -140,20 +116,22 @@ public class LedgerTransactionData implements LedgerTransaction { | |||||
this.transactionContent = content; | this.transactionContent = content; | ||||
} | } | ||||
public void setEndpointSignatures(Object[] participantSignatures) { | |||||
int length = participantSignatures.length; | |||||
this.endpointSignatures = new DigitalSignature[length]; | |||||
for (int i = 0; i < length; i++) { | |||||
this.endpointSignatures[i] = (DigitalSignature) participantSignatures[i]; | |||||
} | |||||
public void setEndpointSignatures(DigitalSignature[] participantSignatures) { | |||||
this.endpointSignatures = participantSignatures; | |||||
// int length = participantSignatures.length; | |||||
// this.endpointSignatures = new DigitalSignature[length]; | |||||
// for (int i = 0; i < length; i++) { | |||||
// this.endpointSignatures[i] = (DigitalSignature) participantSignatures[i]; | |||||
// } | |||||
} | } | ||||
public void setNodeSignatures(Object[] nodeSignatures) { | |||||
int length = nodeSignatures.length; | |||||
this.nodeSignatures = new DigitalSignature[length]; | |||||
for (int i = 0; i < length; i++) { | |||||
this.nodeSignatures[i] = (DigitalSignature) nodeSignatures[i]; | |||||
} | |||||
public void setNodeSignatures(DigitalSignature[] nodeSignatures) { | |||||
this.nodeSignatures = nodeSignatures; | |||||
// int length = nodeSignatures.length; | |||||
// this.nodeSignatures = new DigitalSignature[length]; | |||||
// for (int i = 0; i < length; i++) { | |||||
// this.nodeSignatures[i] = (DigitalSignature) nodeSignatures[i]; | |||||
// } | |||||
} | } | ||||
public void setExecutionState(TransactionState executionState) { | public void setExecutionState(TransactionState executionState) { |
@@ -0,0 +1,630 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.List; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||||
import com.jd.blockchain.crypto.Crypto; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.BlockBody; | |||||
import com.jd.blockchain.ledger.BlockRollbackException; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.IllegalTransactionException; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.LedgerDataSnapshot; | |||||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||||
import com.jd.blockchain.ledger.LedgerSettings; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | |||||
import com.jd.blockchain.ledger.OperationResult; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
import com.jd.blockchain.ledger.TransactionRollbackException; | |||||
import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||||
import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
public class LedgerTransactionalEditor implements LedgerEditor { | |||||
private static final boolean PARALLEL_DB_WRITE; | |||||
static { | |||||
PARALLEL_DB_WRITE = Boolean.getBoolean("parallel-dbwrite"); | |||||
System.out.println("------ [[ parallel-dbwrite=" + PARALLEL_DB_WRITE + " ]] ------"); | |||||
} | |||||
/** | |||||
* 账本Hash,创世区块的编辑器则返回 null; | |||||
*/ | |||||
private HashDigest ledgerHash; | |||||
private final String ledgerKeyPrefix; | |||||
private CryptoSetting cryptoSetting; | |||||
private LedgerBlockData currentBlock; | |||||
// private Stack<StagedSnapshot> stagedSnapshots = new Stack<>(); | |||||
private boolean prepared = false; | |||||
private boolean canceled = false; | |||||
private boolean committed = false; | |||||
private StagedSnapshot startingPoint; | |||||
/** | |||||
* 当前区块的存储; | |||||
*/ | |||||
private BufferedKVStorage baseStorage; | |||||
/** | |||||
* 上一个交易产生的账本快照; | |||||
*/ | |||||
private TxSnapshot previousTxSnapshot; | |||||
/** | |||||
* 当前交易的上下文; | |||||
*/ | |||||
private volatile LedgerTransactionContextImpl currentTxCtx; | |||||
/** | |||||
* 最后提交的账本数据集; | |||||
*/ | |||||
private volatile LedgerDataset latestLedgerDataset; | |||||
/** | |||||
* 最后提交的交易集合; | |||||
*/ | |||||
private volatile TransactionSet latestTransactionSet; | |||||
/** | |||||
* @param ledgerHash | |||||
* @param cryptoSetting | |||||
* @param currentBlock | |||||
* @param startingPoint | |||||
* @param ledgerKeyPrefix | |||||
* @param bufferedStorage | |||||
* @param verifyTx 是否校验交易请求;当外部调用者在调用前已经实施了验证时,将次参数设置为 false 能够提升性能; | |||||
*/ | |||||
private LedgerTransactionalEditor(HashDigest ledgerHash, CryptoSetting cryptoSetting, LedgerBlockData currentBlock, | |||||
StagedSnapshot startingPoint, String ledgerKeyPrefix, BufferedKVStorage bufferedStorage) { | |||||
this.ledgerHash = ledgerHash; | |||||
this.ledgerKeyPrefix = ledgerKeyPrefix; | |||||
this.cryptoSetting = cryptoSetting; | |||||
this.currentBlock = currentBlock; | |||||
this.baseStorage = bufferedStorage; | |||||
this.startingPoint = startingPoint; | |||||
// this.stagedSnapshots.push(startingPoint); | |||||
} | |||||
/** | |||||
* 创建账本新区块的编辑器; | |||||
* | |||||
* @param ledgerHash 账本哈希; | |||||
* @param ledgerSetting 账本设置; | |||||
* @param previousBlock 前置区块; | |||||
* @param ledgerKeyPrefix 账本数据前缀; | |||||
* @param ledgerExStorage 账本数据存储; | |||||
* @param ledgerVerStorage 账本数据版本化存储; | |||||
* @param verifyTx 是否校验交易请求;当外部调用者在调用前已经实施了验证时,将次参数设置为 false 能够提升性能; | |||||
* @return | |||||
*/ | |||||
public static LedgerTransactionalEditor createEditor(LedgerBlock previousBlock, LedgerSettings ledgerSetting, | |||||
String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
// new block; | |||||
HashDigest ledgerHash = previousBlock.getLedgerHash(); | |||||
if (ledgerHash == null) { | |||||
ledgerHash = previousBlock.getHash(); | |||||
} | |||||
if (ledgerHash == null) { | |||||
throw new IllegalArgumentException("Illegal previous block was specified!"); | |||||
} | |||||
LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, ledgerHash, | |||||
previousBlock.getHash()); | |||||
// init storage; | |||||
BufferedKVStorage txStagedStorage = new BufferedKVStorage(ledgerExStorage, ledgerVerStorage, PARALLEL_DB_WRITE); | |||||
StagedSnapshot startingPoint = new TxSnapshot(previousBlock, previousBlock.getTransactionSetHash()); | |||||
// instantiate editor; | |||||
return new LedgerTransactionalEditor(ledgerHash, ledgerSetting.getCryptoSetting(), currBlock, startingPoint, | |||||
ledgerKeyPrefix, txStagedStorage); | |||||
} | |||||
/** | |||||
* 创建创世区块的编辑器; | |||||
* | |||||
* @param initSetting | |||||
* @param ledgerKeyPrefix | |||||
* @param ledgerExStorage | |||||
* @param ledgerVerStorage | |||||
* @param verifyTx 是否校验交易请求;当外部调用者在调用前已经实施了验证时,将次参数设置为 false 能够提升性能; | |||||
* @return | |||||
*/ | |||||
public static LedgerTransactionalEditor createEditor(LedgerInitSetting initSetting, String ledgerKeyPrefix, | |||||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||||
LedgerBlockData genesisBlock = new LedgerBlockData(0, null, null); | |||||
StagedSnapshot startingPoint = new GenesisSnapshot(initSetting); | |||||
// init storage; | |||||
BufferedKVStorage txStagedStorage = new BufferedKVStorage(ledgerExStorage, ledgerVerStorage, false); | |||||
return new LedgerTransactionalEditor(null, initSetting.getCryptoSetting(), genesisBlock, startingPoint, | |||||
ledgerKeyPrefix, txStagedStorage); | |||||
} | |||||
private void commitTxSnapshot(TxSnapshot snapshot) { | |||||
previousTxSnapshot = snapshot; | |||||
latestLedgerDataset = currentTxCtx.getDataset(); | |||||
latestLedgerDataset.setReadonly(); | |||||
latestTransactionSet = currentTxCtx.getTransactionSet(); | |||||
latestTransactionSet.setReadonly(); | |||||
currentTxCtx = null; | |||||
} | |||||
private void rollbackCurrentTx() { | |||||
currentTxCtx = null; | |||||
} | |||||
LedgerBlock getCurrentBlock() { | |||||
return currentBlock; | |||||
} | |||||
@Override | |||||
public long getBlockHeight() { | |||||
return currentBlock.getHeight(); | |||||
} | |||||
@Override | |||||
public HashDigest getLedgerHash() { | |||||
return ledgerHash; | |||||
} | |||||
@Override | |||||
public LedgerDataset getLedgerDataset() { | |||||
return latestLedgerDataset; | |||||
} | |||||
@Override | |||||
public TransactionSet getTransactionSet() { | |||||
return latestTransactionSet; | |||||
} | |||||
/** | |||||
* 检查当前账本是否是指定交易请求的账本; | |||||
* | |||||
* @param txRequest | |||||
* @return | |||||
*/ | |||||
private boolean isRequestMatched(TransactionRequest txRequest) { | |||||
HashDigest reqLedgerHash = txRequest.getTransactionContent().getLedgerHash(); | |||||
if (ledgerHash == reqLedgerHash) { | |||||
return true; | |||||
} | |||||
if (ledgerHash == null || reqLedgerHash == null) { | |||||
return false; | |||||
} | |||||
return ledgerHash.equals(reqLedgerHash); | |||||
} | |||||
/** | |||||
* 注:此方法不验证交易完整性和签名有效性,仅仅设计为进行交易记录的管理;调用者应在此方法之外进行数据完整性和签名有效性的检查; | |||||
*/ | |||||
@Override | |||||
public synchronized LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | |||||
// if (SettingContext.txSettings().verifyLedger() && !isRequestMatched(txRequest)) { | |||||
if (!isRequestMatched(txRequest)) { | |||||
throw new IllegalTransactionException( | |||||
"Transaction request is dispatched to a wrong ledger! --[TxHash=" | |||||
+ txRequest.getTransactionContent().getHash() + "]!", | |||||
TransactionState.IGNORED_BY_WRONG_LEDGER); | |||||
} | |||||
if (currentTxCtx != null) { | |||||
throw new IllegalStateException( | |||||
"Unable to open another new transaction before the current transaction is completed! --[TxHash=" | |||||
+ txRequest.getTransactionContent().getHash() + "]!"); | |||||
} | |||||
// 检查状态是否允许创建新的交易请求;; | |||||
checkState(); | |||||
// init storage of new transaction; | |||||
BufferedKVStorage txBufferedStorage = new BufferedKVStorage(baseStorage, baseStorage, false); | |||||
LedgerDataset txDataset = null; | |||||
TransactionSet txset = null; | |||||
if (previousTxSnapshot == null) { | |||||
// load the starting point of the new transaction; | |||||
if (startingPoint instanceof GenesisSnapshot) { | |||||
// 准备生成创世区块; | |||||
GenesisSnapshot snpht = (GenesisSnapshot) startingPoint; | |||||
txDataset = LedgerRepositoryImpl.newDataSet(snpht.initSetting, ledgerKeyPrefix, txBufferedStorage, | |||||
txBufferedStorage); | |||||
txset = LedgerRepositoryImpl.newTransactionSet(txDataset.getAdminDataset().getSettings(), | |||||
ledgerKeyPrefix, txBufferedStorage, txBufferedStorage); | |||||
} else if (startingPoint instanceof TxSnapshot) { | |||||
// 新的区块; | |||||
// TxSnapshot; reload dataset and txset; | |||||
TxSnapshot snpht = (TxSnapshot) startingPoint; | |||||
// load dataset; | |||||
txDataset = LedgerRepositoryImpl.loadDataSet(snpht.dataSnapshot, cryptoSetting, ledgerKeyPrefix, | |||||
txBufferedStorage, txBufferedStorage, false); | |||||
// load txset; | |||||
txset = LedgerRepositoryImpl.loadTransactionSet(snpht.txsetHash, cryptoSetting, ledgerKeyPrefix, | |||||
txBufferedStorage, txBufferedStorage, false); | |||||
} else { | |||||
// Unreachable; | |||||
throw new IllegalStateException("Unreachable code was accidentally executed!"); | |||||
} | |||||
} else { | |||||
// Reuse previous object to optimize performance; | |||||
// load dataset; | |||||
txDataset = LedgerRepositoryImpl.loadDataSet(previousTxSnapshot.dataSnapshot, cryptoSetting, | |||||
ledgerKeyPrefix, txBufferedStorage, txBufferedStorage, false); | |||||
// load txset; | |||||
txset = LedgerRepositoryImpl.loadTransactionSet(previousTxSnapshot.txsetHash, cryptoSetting, | |||||
ledgerKeyPrefix, txBufferedStorage, txBufferedStorage, false); | |||||
} | |||||
currentTxCtx = new LedgerTransactionContextImpl(txRequest, txDataset, txset, txBufferedStorage, this); | |||||
return currentTxCtx; | |||||
} | |||||
@Override | |||||
public LedgerBlock prepare() { | |||||
checkState(); | |||||
if (currentTxCtx != null) { | |||||
// 有进行中的交易尚未提交或回滚; | |||||
throw new IllegalStateException( | |||||
"There is an ongoing transaction that has been not committed or rolled back!"); | |||||
} | |||||
if (previousTxSnapshot == null) { | |||||
// 当前区块没有加入过交易,不允许产生空区块; | |||||
throw new IllegalStateException( | |||||
"There is no transaction in the current block, and no empty blocks is allowed!"); | |||||
} | |||||
// do commit when transaction isolation level is BLOCK; | |||||
currentBlock.setAdminAccountHash(previousTxSnapshot.getAdminAccountHash()); | |||||
currentBlock.setUserAccountSetHash(previousTxSnapshot.getUserAccountSetHash()); | |||||
currentBlock.setDataAccountSetHash(previousTxSnapshot.getDataAccountSetHash()); | |||||
currentBlock.setContractAccountSetHash(previousTxSnapshot.getContractAccountSetHash()); | |||||
currentBlock.setTransactionSetHash(previousTxSnapshot.getTransactionSetHash()); | |||||
// TODO: 根据所有交易的时间戳的平均值来生成区块的时间戳; | |||||
// long timestamp = | |||||
// currentBlock.setTimestamp(timestamp); | |||||
// compute block hash; | |||||
byte[] blockBodyBytes = BinaryProtocol.encode(currentBlock, BlockBody.class); | |||||
HashDigest blockHash = Crypto.getHashFunction(cryptoSetting.getHashAlgorithm()).hash(blockBodyBytes); | |||||
currentBlock.setHash(blockHash); | |||||
// if (currentBlock.getLedgerHash() == null) { | |||||
// // init GenesisBlock's ledger hash; | |||||
// currentBlock.setLedgerHash(blockHash); | |||||
// } | |||||
// persist block bytes; | |||||
// only one version per block; | |||||
byte[] blockBytes = BinaryProtocol.encode(currentBlock, LedgerBlock.class); | |||||
Bytes blockStorageKey = LedgerRepositoryImpl.encodeBlockStorageKey(currentBlock.getHash()); | |||||
long v = baseStorage.set(blockStorageKey, blockBytes, -1); | |||||
if (v < 0) { | |||||
throw new IllegalStateException( | |||||
"Block already exist! --[BlockHash=" + Base58Utils.encode(currentBlock.getHash().toBytes()) + "]"); | |||||
} | |||||
// persist block hash to ledger index; | |||||
HashDigest ledgerHash = currentBlock.getLedgerHash(); | |||||
if (ledgerHash == null) { | |||||
ledgerHash = blockHash; | |||||
} | |||||
Bytes ledgerIndexKey = LedgerRepositoryImpl.encodeLedgerIndexKey(ledgerHash); | |||||
long expectedVersion = currentBlock.getHeight() - 1; | |||||
v = baseStorage.set(ledgerIndexKey, currentBlock.getHash().toBytes(), expectedVersion); | |||||
if (v < 0) { | |||||
throw new IllegalStateException( | |||||
String.format("Index of BlockHash already exist! --[BlockHeight=%s][BlockHash=%s]", | |||||
currentBlock.getHeight(), currentBlock.getHash())); | |||||
} | |||||
prepared = true; | |||||
return currentBlock; | |||||
} | |||||
@Override | |||||
public void commit() { | |||||
if (committed) { | |||||
throw new IllegalStateException("The current block has been committed!"); | |||||
} | |||||
if (canceled) { | |||||
throw new IllegalStateException("The current block has been canceled!"); | |||||
} | |||||
if (!prepared) { | |||||
// 未就绪; | |||||
throw new IllegalStateException("The current block is not ready yet!"); | |||||
} | |||||
baseStorage.flush(); | |||||
committed = true; | |||||
} | |||||
@Override | |||||
public void cancel() { | |||||
if (committed) { | |||||
throw new IllegalStateException("The current block has been committed!"); | |||||
} | |||||
if (canceled) { | |||||
return; | |||||
} | |||||
canceled = true; | |||||
baseStorage.cancel(); | |||||
} | |||||
private void checkState() { | |||||
if (prepared) { | |||||
throw new IllegalStateException("The current block is ready!"); | |||||
} | |||||
if (committed) { | |||||
throw new IllegalStateException("The current block has been committed!"); | |||||
} | |||||
if (canceled) { | |||||
throw new IllegalStateException("The current block has been canceled!"); | |||||
} | |||||
} | |||||
// --------------------------- inner type -------------------------- | |||||
/** | |||||
* 用于暂存交易上下文数据的快照对象; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
private static interface StagedSnapshot { | |||||
} | |||||
/** | |||||
* 创世区块的快照对象; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
private static class GenesisSnapshot implements StagedSnapshot { | |||||
private LedgerInitSetting initSetting; | |||||
public GenesisSnapshot(LedgerInitSetting initSetting) { | |||||
this.initSetting = initSetting; | |||||
} | |||||
} | |||||
/** | |||||
* 交易执行完毕后的快照对象; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
private static class TxSnapshot implements StagedSnapshot { | |||||
/** | |||||
* 账本数据的快照; | |||||
*/ | |||||
private LedgerDataSnapshot dataSnapshot; | |||||
/** | |||||
* 交易集合的快照(根哈希); | |||||
*/ | |||||
private HashDigest txsetHash; | |||||
public HashDigest getAdminAccountHash() { | |||||
return dataSnapshot.getAdminAccountHash(); | |||||
} | |||||
public HashDigest getUserAccountSetHash() { | |||||
return dataSnapshot.getUserAccountSetHash(); | |||||
} | |||||
public HashDigest getDataAccountSetHash() { | |||||
return dataSnapshot.getDataAccountSetHash(); | |||||
} | |||||
public HashDigest getContractAccountSetHash() { | |||||
return dataSnapshot.getContractAccountSetHash(); | |||||
} | |||||
public HashDigest getTransactionSetHash() { | |||||
return txsetHash; | |||||
} | |||||
public TxSnapshot(LedgerDataSnapshot dataSnapshot, HashDigest txsetHash) { | |||||
this.dataSnapshot = dataSnapshot; | |||||
this.txsetHash = txsetHash; | |||||
} | |||||
} | |||||
/** | |||||
* 交易的上下文; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
private static class LedgerTransactionContextImpl implements LedgerTransactionContext { | |||||
private LedgerTransactionalEditor blockEditor; | |||||
private TransactionRequest txRequest; | |||||
private LedgerDataset dataset; | |||||
private TransactionSet txset; | |||||
private BufferedKVStorage storage; | |||||
private boolean committed = false; | |||||
private boolean rollbacked = false; | |||||
private LedgerTransaction transaction; | |||||
private HashDigest txRootHash; | |||||
private LedgerTransactionContextImpl(TransactionRequest txRequest, LedgerDataset dataset, | |||||
TransactionSet txset, BufferedKVStorage storage, LedgerTransactionalEditor editor) { | |||||
this.txRequest = txRequest; | |||||
this.dataset = dataset; | |||||
this.txset = txset; | |||||
this.storage = storage; | |||||
this.blockEditor = editor; | |||||
} | |||||
@Override | |||||
public LedgerDataset getDataset() { | |||||
return dataset; | |||||
} | |||||
@Override | |||||
public TransactionSet getTransactionSet() { | |||||
return txset; | |||||
} | |||||
@Override | |||||
public TransactionRequest getTransactionRequest() { | |||||
return txRequest; | |||||
} | |||||
@Override | |||||
public LedgerTransaction commit(TransactionState txResult) { | |||||
return commit(txResult, null); | |||||
} | |||||
@Override | |||||
public LedgerTransaction commit(TransactionState txResult, List<OperationResult> operationResults) { | |||||
checkTxState(); | |||||
// capture snapshot | |||||
this.dataset.commit(); | |||||
TransactionStagedSnapshot txDataSnapshot = takeDataSnapshot(); | |||||
LedgerTransactionData tx; | |||||
try { | |||||
tx = new LedgerTransactionData(blockEditor.getBlockHeight(), txRequest, txResult, txDataSnapshot, | |||||
operationResultArray(operationResults)); | |||||
this.txset.add(tx); | |||||
this.txset.commit(); | |||||
} catch (Exception e) { | |||||
throw new TransactionRollbackException(e.getMessage(), e); | |||||
} | |||||
try { | |||||
this.storage.flush(); | |||||
} catch (Exception e) { | |||||
throw new BlockRollbackException(e.getMessage(), e); | |||||
} | |||||
// put snapshot into stack; | |||||
TxSnapshot snapshot = new TxSnapshot(txDataSnapshot, txset.getRootHash()); | |||||
blockEditor.commitTxSnapshot(snapshot); | |||||
committed = true; | |||||
return tx; | |||||
} | |||||
@Override | |||||
public LedgerTransaction discardAndCommit(TransactionState txResult) { | |||||
return discardAndCommit(txResult, null); | |||||
} | |||||
@Override | |||||
public LedgerTransaction discardAndCommit(TransactionState txResult, List<OperationResult> operationResults) { | |||||
checkTxState(); | |||||
// 未处理 | |||||
dataset.cancel(); | |||||
TransactionStagedSnapshot txDataSnapshot = takeDataSnapshot(); | |||||
LedgerTransactionData tx; | |||||
try { | |||||
tx = new LedgerTransactionData(blockEditor.getBlockHeight(), txRequest, txResult, txDataSnapshot, | |||||
operationResultArray(operationResults)); | |||||
this.txset.add(tx); | |||||
this.txset.commit(); | |||||
} catch (Exception e) { | |||||
throw new TransactionRollbackException(e.getMessage(), e); | |||||
} | |||||
try { | |||||
this.storage.flush(); | |||||
} catch (Exception e) { | |||||
throw new BlockRollbackException(e.getMessage(), e); | |||||
} | |||||
// put snapshot into stack; | |||||
TxSnapshot snapshot = new TxSnapshot(txDataSnapshot, txset.getRootHash()); | |||||
blockEditor.commitTxSnapshot(snapshot); | |||||
committed = true; | |||||
return tx; | |||||
} | |||||
private TransactionStagedSnapshot takeDataSnapshot() { | |||||
TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot(); | |||||
txDataSnapshot.setAdminAccountHash(dataset.getAdminDataset().getHash()); | |||||
txDataSnapshot.setContractAccountSetHash(dataset.getContractAccountset().getRootHash()); | |||||
txDataSnapshot.setDataAccountSetHash(dataset.getDataAccountSet().getRootHash()); | |||||
txDataSnapshot.setUserAccountSetHash(dataset.getUserAccountSet().getRootHash()); | |||||
return txDataSnapshot; | |||||
} | |||||
private OperationResult[] operationResultArray(List<OperationResult> operationResults) { | |||||
OperationResult[] operationResultArray = null; | |||||
if (operationResults != null && !operationResults.isEmpty()) { | |||||
operationResultArray = new OperationResult[operationResults.size()]; | |||||
operationResults.toArray(operationResultArray); | |||||
} | |||||
return operationResultArray; | |||||
} | |||||
@Override | |||||
public void rollback() { | |||||
if (this.rollbacked) { | |||||
return; | |||||
} | |||||
if (this.committed) { | |||||
throw new IllegalStateException("This transaction had been committed!"); | |||||
} | |||||
dataset.cancel(); | |||||
storage.cancel(); | |||||
blockEditor.rollbackCurrentTx(); | |||||
rollbacked = true; | |||||
} | |||||
private void checkTxState() { | |||||
if (this.committed) { | |||||
throw new IllegalStateException("This transaction had been committed!"); | |||||
} | |||||
if (this.rollbacked) { | |||||
throw new IllegalStateException("This transaction had been rollbacked!"); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,5 +1,6 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.storage.service.VersioningKVEntry; | import com.jd.blockchain.storage.service.VersioningKVEntry; | ||||
public interface MerkleDataEntry { | public interface MerkleDataEntry { | ||||