All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jd.blockchain.sdk.service.PeerBlockchainServiceFactory Maven / Gradle / Ivy

package com.jd.blockchain.sdk.service;

import com.jd.blockchain.consensus.*;
import com.jd.blockchain.consensus.client.ClientFactory;
import com.jd.blockchain.consensus.client.ClientSettings;
import com.jd.blockchain.consensus.client.ConsensusClient;
import com.jd.blockchain.consensus.service.MonitorService;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.sdk.*;
import com.jd.blockchain.sdk.proxy.HttpBlockchainQueryService;
import com.jd.blockchain.sdk.service.ConsensusClientManager.ConsensusClientFactory;
import com.jd.blockchain.setting.GatewayAuthResponse;
import com.jd.blockchain.setting.LedgerIncomingSettings;
import com.jd.blockchain.transaction.BlockchainQueryService;
import com.jd.blockchain.transaction.TransactionService;
import com.jd.httpservice.agent.HttpServiceAgent;
import com.jd.httpservice.agent.ServiceConnection;
import com.jd.httpservice.agent.ServiceConnectionManager;
import com.jd.httpservice.agent.ServiceEndpoint;

import utils.io.ByteArray;
import utils.net.NetworkAddress;
import utils.security.AuthenticationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

public class PeerBlockchainServiceFactory implements BlockchainServiceFactory, Closeable {

	private static Logger LOGGER = LoggerFactory.getLogger(PeerBlockchainServiceFactory.class);

	private static final Map peerBlockchainServiceFactories = new ConcurrentHashMap<>();

	private static final Map peerManageServices = new ConcurrentHashMap<>();

	private static final Map> peerLedgers = new ConcurrentHashMap<>();

	private final Map accessContextMap = new ConcurrentHashMap<>();

	private final Map monitorServiceMap = new ConcurrentHashMap<>();

	private ServiceConnectionManager httpConnectionManager;

	private PeerServiceProxy peerServiceProxy;

	/**
	 * 创建共识节点的区块链服务工厂;
	 * 
	 * @param credential            经过认证的客户端凭证;
	 * @param httpConnectionManager Http请求管理器;
	 * @param accessableLedgers     可用账本列表;
	 */
	protected PeerBlockchainServiceFactory(ServiceConnectionManager httpConnectionManager,
			LedgerAccessContextImpl[] accessableLedgers) {
		this.httpConnectionManager = httpConnectionManager;
		this.peerServiceProxy = new PeerServiceProxy(accessableLedgers);
	}

	public void addLedgerAccessContexts(LedgerAccessContextImpl[] accessContexts) {
		this.peerServiceProxy.addLedgerAccessContexts(accessContexts);
	}

	public HashDigest[] getLedgerHashs() {
		return accessContextMap.keySet().toArray(new HashDigest[accessContextMap.size()]);
	}

	public SessionCredential getCredential(HashDigest ledgerHash) {
		LedgerAccessContextImpl ledgerAccessContext = accessContextMap.get(ledgerHash);
		if (ledgerAccessContext == null) {
			return null;
		}
		return ledgerAccessContext.getCredential();
	}

	@Override
	public PeerBlockchainService getBlockchainService() {
		return peerServiceProxy;
	}

	/**
	 * 返回交易服务;
	 *
	 * 
* * 返回的交易服务聚合了该节点绑定的多个账本的交易服务,并根据交易请求中指定的目标账本选择相应的交易服务进行转发; * * @return */ public TransactionService getTransactionService() { return peerServiceProxy; } /** * 连接到指定的共识节点; * * @param peerAddr 提供对网关接入认证的节点的认证地址列表;
* 按列表的先后顺序连接节点进行认证,从第一个成功通过的节点请求整个区块链网络的拓扑配置,并建立起和整个区块链网络的连接;
* 此参数指定的节点列表可以是整个区块链网络的全部节点的子集,而不必包含所有节点; * * @return 区块链服务工厂实例; */ public static PeerBlockchainServiceFactory connect(AsymmetricKeypair gatewayKey, NetworkAddress peerAddr, SessionCredentialProvider credentialProvider, ConsensusClientManager clientManager) { GatewayAuthResponse gatewayAuthResponse = auth(gatewayKey, peerAddr, credentialProvider); PeerBlockchainServiceFactory factory = null; ServiceConnectionManager httpConnectionManager; PeerBlockchainQueryService peerManageService; if (peerBlockchainServiceFactories.containsKey(peerAddr)) { factory = peerBlockchainServiceFactories.get(peerAddr); httpConnectionManager = factory.httpConnectionManager; } else { httpConnectionManager = new ServiceConnectionManager(); } if (peerManageServices.containsKey(peerAddr)) { peerManageService = peerManageServices.get(peerAddr); } else { ServiceConnection httpConnection = httpConnectionManager.create(new ServiceEndpoint(peerAddr)); peerManageService = new PeerBlockchainQueryService(httpConnection, HttpServiceAgent.createService(HttpBlockchainQueryService.class, httpConnection, null)); peerManageServices.put(peerAddr, peerManageService); } LedgerIncomingSettings[] ledgerSettingsArray = gatewayAuthResponse.getLedgers(); // 判断当前节点对应账本是否一致 List needInitSettings = new ArrayList<>(); Set currentPeerLedgers = peerLedgers.computeIfAbsent(peerAddr, k -> new HashSet<>()); for (LedgerIncomingSettings ledgerIncomingSetting : ledgerSettingsArray) { HashDigest currLedgerHash = ledgerIncomingSetting.getLedgerHash(); if (!currentPeerLedgers.contains(currLedgerHash)) { LOGGER.info("Peer[{}] find new ledger [{}]", peerAddr, currLedgerHash.toBase58()); needInitSettings.add(ledgerIncomingSetting); } } if (!needInitSettings.isEmpty()) { LedgerAccessContextImpl[] accessAbleLedgers = new LedgerAccessContextImpl[needInitSettings.size()]; BlockchainQueryService queryService = peerManageService.getQueryService(); Map tempAccessCtxs = new HashMap<>(); Map tempMonitors = new HashMap<>(); for (int i = 0; i < needInitSettings.size(); i++) { LedgerIncomingSettings ledgerSetting = needInitSettings.get(i); String providerName = ledgerSetting.getProviderName(); ConsensusProvider provider = ConsensusProviders.getProvider(providerName); byte[] clientSettingBytes = ByteArray.fromBase64(ledgerSetting.getConsensusClientSettings()); ClientIncomingSettings clientIncomingSettings = provider.getSettingsFactory() .getIncomingSettingsEncoder().decode(clientSettingBytes); SessionCredential sessionCredential = clientIncomingSettings.getCredential(); ConsensusClient consensusClient = clientManager.getConsensusClient(ledgerSetting.getLedgerHash(), sessionCredential, new ConsensusClientFactory() { @Override public ConsensusClient create() { ClientFactory clientFactory = provider.getClientFactory(); ClientSettings clientSettings = clientFactory .buildClientSettings(clientIncomingSettings); return clientFactory.setupClient(clientSettings); } }); // ClientFactory clientFactory = provider.getClientFactory(); // ClientSettings clientSettings = clientFactory.buildClientSettings(clientIncomingSettings); // consensusClient= clientFactory.setupClient(clientSettings); MonitorService monitorService = null; TransactionService autoSigningTxProcService = enableGatewayAutoSigning(gatewayKey, ledgerSetting.getCryptoSetting(), consensusClient); if (autoSigningTxProcService instanceof NodeSigningAppender) { monitorService = new PeerMonitorHandler((((NodeSigningAppender) autoSigningTxProcService))); } LedgerAccessContextImpl accCtx = new LedgerAccessContextImpl(sessionCredential); accCtx.ledgerHash = ledgerSetting.getLedgerHash(); accCtx.cryptoSetting = ledgerSetting.getCryptoSetting(); accCtx.queryService = queryService; accCtx.txProcService = autoSigningTxProcService; accCtx.consensusClient = consensusClient; accessAbleLedgers[i] = accCtx; tempAccessCtxs.put(accCtx.ledgerHash, accCtx); // 添加对应Hash到该Peer节点 currentPeerLedgers.add(accCtx.ledgerHash); if (monitorService != null) { tempMonitors.put(accCtx.ledgerHash, monitorService); } // 保存会话凭证;如果出错不影响后续执行; updateSessionCredential(ledgerSetting.getLedgerHash(), sessionCredential, credentialProvider); } if (factory == null) { // 第一次连接成功 factory = new PeerBlockchainServiceFactory(httpConnectionManager, accessAbleLedgers); factory.accessContextMap.putAll(tempAccessCtxs); factory.monitorServiceMap.putAll(tempMonitors); peerBlockchainServiceFactories.put(peerAddr, factory); if (!tempAccessCtxs.isEmpty()) { for (HashDigest hash : tempAccessCtxs.keySet()) { LOGGER.info("First connect, peer[{}] init new ledger[{}] OK !!!", peerAddr, hash.toBase58()); } } } else { factory.accessContextMap.putAll(tempAccessCtxs); factory.monitorServiceMap.putAll(tempMonitors); factory.addLedgerAccessContexts(accessAbleLedgers); if (!tempAccessCtxs.isEmpty()) { for (HashDigest hash : tempAccessCtxs.keySet()) { LOGGER.info("Reconnect, peer[{}] init new ledger[{}] OK !!!", peerAddr, hash.toBase58()); } } } } // End of: if (!needInitSettings.isEmpty()); return factory; // ServiceConnectionManager httpConnectionManager = new ServiceConnectionManager(); // ServiceConnection httpConnection = httpConnectionManager.create(new ServiceEndpoint(peerAddr)); // BlockchainQueryService queryService = HttpServiceAgent.createService(HttpBlockchainQueryService.class, // httpConnection, null); // // LedgerIncomingSetting[] ledgerSettings = incomingSetting.getLedgers(); // // LedgerAccessContextImpl[] accessAbleLedgers = new LedgerAccessContextImpl[ledgerSettings.length]; // for (int i = 0; i < ledgerSettings.length; i++) { // LedgerIncomingSetting ledgerSetting = ledgerSettings[i]; // String providerName = ledgerSetting.getProviderName(); // ConsensusProvider provider = ConsensusProviders.getProvider(providerName); // byte[] clientSettingBytes = ByteArray.fromBase64(ledgerSetting.getClientSetting()); // // ClientIncomingSettings clientIncomingSettings = provider.getSettingsFactory().getIncomingSettingsEncoder().decode(clientSettingBytes); // ClientFactory clientFactory = provider.getClientFactory(); // ClientSettings clientSettings = clientFactory.buildClientSettings(clientIncomingSettings); // ConsensusClient consensusClient = clientFactory.setupClient(clientSettings); // // TransactionService autoSigningTxProcService = enableGatewayAutoSigning(gatewayKey, // ledgerSetting.getCryptoSetting(), consensusClient); // // // LedgerAccessContextImpl accCtx = new LedgerAccessContextImpl(); // accCtx.ledgerHash = ledgerSetting.getLedgerHash(); // accCtx.cryptoSetting = ledgerSetting.getCryptoSetting(); // accCtx.queryService = queryService; // accCtx.txProcService = autoSigningTxProcService; // accCtx.consensusClient = consensusClient; // // accessAbleLedgers[i] = accCtx; // // accessContextMap.put(accCtx.ledgerHash, accCtx); // } // // PeerBlockchainServiceFactory factory = new PeerBlockchainServiceFactory(httpConnectionManager, // accessAbleLedgers); // return factory; } private static void updateSessionCredential(HashDigest ledgerHash, SessionCredential sessionCredential, SessionCredentialProvider credentialProvider) { try { // 保存会话凭证; credentialProvider.setCredential(ledgerHash.toBase58(), sessionCredential); } catch (Exception e) { // 如果出错不影响后续执行; LOGGER.warn("Error occurred while update consensus session credential of ledger[" + ledgerHash.toBase58() + "]! ", e); } } private static GatewayAuthResponse auth(AsymmetricKeypair gatewayKey, NetworkAddress peerAddr, SessionCredentialProvider sessionCredentials) { try { ManagementHttpService gatewayMngService = getManageService(peerAddr); // 获得节点的信息; AccessSpecification accSpec = gatewayMngService.getAccessSpecification(); Map ledgerProviderMap = accSpec.asMap(); GatewayAuthRequestConfig authRequest = new GatewayAuthRequestConfig(); for (Entry ledgerProvider : ledgerProviderMap.entrySet()) { ConsensusProvider provider = ConsensusProviders.getProvider(ledgerProvider.getValue()); ClientFactory clientFactory = provider.getClientFactory(); // 加载本地的历史凭证; SessionCredential sessionCredential = sessionCredentials .getCredential(ledgerProvider.getKey().toBase58()); ClientCredential authId = clientFactory.buildCredential(sessionCredential, gatewayKey); authRequest.add(ledgerProvider.getKey(), authId); } // 接入认证,获得接入配置; // 传递网关账户地址及签名; GatewayAuthResponse gatewayAuthResponse = gatewayMngService.authenticateGateway(authRequest); return gatewayAuthResponse; } catch (Exception e) { String errorMessage = String.format("Gateway authentication fail! --[peer=%s] %s", peerAddr.toString(), e.getMessage()); LOGGER.warn(errorMessage, e); throw new AuthenticationException(errorMessage); } } private static ManagementHttpService getManageService(NetworkAddress peer) { ServiceEndpoint peerServer = new ServiceEndpoint(peer.getHost(), peer.getPort(), false); ManagementHttpService manageService = HttpServiceAgent.createService(ManagementHttpService.class, peerServer); return manageService; } /** * 启用网关自动签名; * * @param nodeKeyPair * @param cryptoSetting * @return */ private static TransactionService enableGatewayAutoSigning(AsymmetricKeypair nodeKeyPair, CryptoSetting cryptoSetting, ConsensusClient consensusClient) { NodeSigningAppender signingAppender = new NodeSigningAppender(cryptoSetting.getHashAlgorithm(), nodeKeyPair, consensusClient); return signingAppender.init(); } @Override public void close() { try { for (Map.Entry entry : accessContextMap.entrySet()) { LedgerAccessContextImpl ctx = entry.getValue(); ctx.consensusClient.close(); } httpConnectionManager.close(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } // 重连时先清理 public static void clear() { peerBlockchainServiceFactories.clear(); peerManageServices.clear(); peerLedgers.clear(); } public Map getMonitorServiceMap() { return monitorServiceMap; } private static class LedgerAccessContextImpl implements LedgerAccessContext { private HashDigest ledgerHash; private CryptoSetting cryptoSetting; private TransactionService txProcService; private BlockchainQueryService queryService; private ConsensusClient consensusClient; private final SessionCredential credential; public LedgerAccessContextImpl(SessionCredential credential) { this.credential = credential; } /** * 经过认证的客户端凭证; * * @return */ public SessionCredential getCredential() { return credential; } @Override public HashDigest getLedgerHash() { return ledgerHash; } @Override public CryptoSetting getCryptoSetting() { return cryptoSetting; } @Override public TransactionService getTransactionService() { return txProcService; } @Override public BlockchainQueryService getQueryService() { return queryService; } } private static final class PeerBlockchainQueryService { public PeerBlockchainQueryService(ServiceConnection httpConnection, BlockchainQueryService queryService) { this.httpConnection = httpConnection; this.queryService = queryService; } ServiceConnection httpConnection; BlockchainQueryService queryService; public ServiceConnection getHttpConnection() { return httpConnection; } public void setHttpConnection(ServiceConnection httpConnection) { this.httpConnection = httpConnection; } public BlockchainQueryService getQueryService() { return queryService; } public void setQueryService(BlockchainQueryService queryService) { this.queryService = queryService; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy