【quorum源码】quorum tessera源码剖析

【quorum源码】quorum tessera源码剖析tessera是quorum的一种隐私管理器实现,使用Java语言编写,用于对quorum隐私交易的加密、解密和分发。

大家好,又见面了,我是你们的朋友全栈君。

概述

tessera是quorum的一种隐私管理器实现,使用Java语言编写,用于对quorum隐私交易的加密、解密和分发。
原理参考:Quorum工作原理

1. 项目结构

tessera
├── argon2 hash函数库,类似的函数还有pbkdf2、bcrypt、 scrypt
├── cli 使用picocli实现的命令行tessera(包含子命令keygen|keyupdate|admin)
├── config 配置数据模型,给各个模块使用的配置
├── config-migration 提供命令行可以将Constellation TOML转换成Tessera JSON
├── data-migration 创建表结构
├── ddls ddl语句,包含两张表(支持mysq、oracle、postgresql、h2、hsql、sqllite)
├── enclave 提供加密、解密接口/Restful api(调用encryption模块)
├── encryption 生成主密钥、共享密钥、加密解密payload、生成随机数等.实现有ec、jnacl、kalium三种
├── key-generation 公钥私钥生成,包含aws、azure、hashcorp三种实现
├── key-vault 密钥保险箱 ,有aws、azure、hashcorp三种实现,可将密钥保存在这些在线服务上
├── security ssl通信相关工具
├── server 包含两个TesseraServer的实现:1、使用Jersey和Jetty 实现的RestServer;2 WebSocketServer
├── service-locator 获取服务实例,默认使用spring 配置文件 tessera-spring.xml中的定义(不使用注解?)
├── shared 大杂烩,包含一些工具类:控制台密码读取、ReflectCallback、JaxbCallback等CallBack
├── tessera-context 上下文,见下面的RuntimeContext
├── tessera-core 主要包含TransactionManager
├── tessera-data 主要包含EncryptedTransactionDAO、EncryptedRawTransactionDAO的实现
├── tessera-dist 系统launcher入口,包含tessera-spring.xml配置文件
├── tessera-jaxrs 系统RESTful API(OpenAPI)定义
├── tessera-partyinfo 参与者之间的服务发现、p2p连接、推送EncodedPayload到其他节点
├── tessera-sync peer节点之间Transaction的同步
├── test-utils 测试mock工具
└── tests 测试用例
参考下面的接口和类

2. 数据库结构

存储hash和加密playload对应关系

CREATE TABLE ENCRYPTED_TRANSACTION (
ENCODED_PAYLOAD BLOB NOT NULL, 
HASH VARBINARY(100) NOT NULL, 
TIMESTAMP BIGINT, PRIMARY KEY (HASH)
);

CREATE TABLE ENCRYPTED_RAW_TRANSACTION (
ENCRYPTED_KEY BLOB NOT NULL,
ENCRYPTED_PAYLOAD BLOB NOT NULL,
NONCE BLOB NOT NULL,
SENDER BLOB NOT NULL, 
TIMESTAMP BIGINT, 
HASH VARBINARY(100) NOT NULL, PRIMARY KEY (HASH)
);

3. 主要流程

3.1 服务启动

a. 首先通过cli从配置文件tessera-config.json读取配置,根据配置创建运行时上下文(上下文持有当前节点公私钥对,peers列表等引用)
b. 再将当前partyInfo保存到集合中(内存)
c. 根据的serverConfigs循环创建ThirdPartyRestApp、P2PRestApp、Q2TRestApp(未包含EnclaveApplication)Restful服务
d 启动服务监听

顺序图:
在这里插入图片描述
主要代码:
main方法

 PicoCliDelegate picoCliDelegate = new PicoCliDelegate();
LOGGER.debug("Execute PicoCliDelegate with args [{}]",String.join(",",args));
final CliResult cliResult = picoCliDelegate.execute(args);
LOGGER.debug("Executed PicoCliDelegate with args [{}].",String.join(",",args));
CliDelegate.instance().setConfig(cliResult.getConfig().orElse(null));
if (cliResult.isSuppressStartup()) { 

System.exit(0);
}
if (cliResult.getStatus() != 0) { 

System.exit(cliResult.getStatus());
}
final Config config =
cliResult
.getConfig()
.orElseThrow(() -> new NoSuchElementException("No config found. Tessera will not run."));
RuntimeContext runtimeContext = RuntimeContextFactory.newFactory().create(config);
LOGGER.debug("Creating service locator");
ServiceLocator serviceLocator = ServiceLocator.create();
LOGGER.debug("Created service locator {}",serviceLocator);
Set<Object> services = serviceLocator.getServices();
LOGGER.debug("Created {} services",services.size());
services.forEach(o -> LOGGER.debug("Service : {}",o));
services.stream()
.filter(PartyInfoService.class::isInstance)
.map(PartyInfoService.class::cast)
.findAny()
.ifPresent(p -> p.populateStore());
runWebServer(config);   

runWebServer


final List<TesseraServer> servers =
config.getServerConfigs().stream()
.filter(server -> !AppType.ENCLAVE.equals(server.getApp()))
.map(
conf -> { 

Object app =
TesseraAppFactory.create(conf.getCommunicationType(), conf.getApp())
.orElseThrow(
() ->
new IllegalStateException(
"Cant create app for " + conf.getApp()));
return TesseraServerFactory.create(conf.getCommunicationType())
.createServer(conf, Collections.singleton(app));
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
for (TesseraServer ts : servers) { 

ts.start();
}

3.2 交易处理

a.收到交易请求后,将请求交给TransactionManager处理,TransactionManager调用Enclave加密tx(详见下一个流程【加密交易】),根据加密的payload,调用MessageHashFactory生成tx Hash,
b. 调用DAO将数据保存到数据库
c. 循环接收者列表,将加密了的playload推送给其他Tessera节点处理
d.将tx hash使用base64编码后返回给quorum几点

在这里插入图片描述

主要代码:

public SendResponse send(SendRequest sendRequest) { 

final String sender = sendRequest.getFrom();
final PublicKey senderPublicKey =
Optional.ofNullable(sender)
.map(base64Decoder::decode)
.map(PublicKey::from)
.orElseGet(enclave::defaultPublicKey);
final byte[][] recipients =
Stream.of(sendRequest)
.filter(sr -> Objects.nonNull(sr.getTo()))
.flatMap(s -> Stream.of(s.getTo()))
.map(base64Decoder::decode)
.toArray(byte[][]::new);
final List<PublicKey> recipientList = Stream.of(recipients).map(PublicKey::from).collect(Collectors.toList());
recipientList.add(senderPublicKey);
recipientList.addAll(enclave.getForwardingKeys());
final List<PublicKey> recipientListNoDuplicate =
recipientList.stream().distinct().collect(Collectors.toList());
final byte[] raw = sendRequest.getPayload();
final EncodedPayload payload = enclave.encryptPayload(raw, senderPublicKey, recipientListNoDuplicate);
final MessageHash transactionHash =
Optional.of(payload)
.map(EncodedPayload::getCipherText)
.map(messageHashFactory::createFromCipherText)
.get();
final EncryptedTransaction newTransaction =
new EncryptedTransaction(transactionHash, this.payloadEncoder.encode(payload));
this.encryptedTransactionDAO.save(newTransaction);
recipientListNoDuplicate.forEach(
recipient -> { 

final EncodedPayload outgoing = payloadEncoder.forRecipient(payload, recipient);
partyInfoService.publishPayload(outgoing, recipient);
});
final byte[] key = transactionHash.getHashBytes();
final String encodedKey = base64Decoder.encodeToString(key);
return new SendResponse(encodedKey);
}

3.3 加密交易

a. 生成随机主密钥(RMK:NonceMasterKey)和随机数Nonce、接收者随机数Nonce
b.使用步骤a的随机数Nonce和RMK加密message(Transaction Payload)。
c. 根据发送者的公钥从keymanager中获取发送者私钥
d.遍历接收者列表:根据发送者的私钥和接收者的公钥生成共享秘钥,根据共享密钥和接收者随机数加密RMK,最后返回RMK列表
e.返回加密的playload、随机数、RMKs给Transaction Manager
在这里插入图片描述
注:图中使用的Encryptor实现是EllipticalCurveEncryptor

主要代码:

 public EncodedPayload encryptPayload(
final RawTransaction rawTransaction, final List<PublicKey> recipientPublicKeys) { 

final MasterKey masterKey =
this.getMasterKey(
rawTransaction.getFrom(), rawTransaction.getFrom(),
rawTransaction.getNonce(), rawTransaction.getEncryptedKey());
final Nonce recipientNonce = encryptor.randomNonce();
final List<byte[]> encryptedMasterKeys =
buildRecipientMasterKeys(rawTransaction.getFrom(), recipientPublicKeys, recipientNonce, masterKey);
return EncodedPayload.Builder.create()
.withSenderKey(rawTransaction.getFrom())
.withCipherText(rawTransaction.getEncryptedPayload())
.withCipherTextNonce(rawTransaction.getNonce())
.withRecipientBoxes(encryptedMasterKeys)
.withRecipientNonce(recipientNonce)
.withRecipientKeys(recipientPublicKeys)
.build();
}
private List<byte[]> buildRecipientMasterKeys(
final PublicKey senderPublicKey,
final List<PublicKey> recipientPublicKeys,
final Nonce recipientNonce,
final MasterKey masterKey) { 

final PrivateKey privateKey = keyManager.getPrivateKeyForPublicKey(senderPublicKey);
return recipientPublicKeys.stream()
.map(publicKey -> encryptor.computeSharedKey(publicKey, privateKey))
.map(sharedKey -> encryptor.sealAfterPrecomputation(masterKey.getKeyBytes(), recipientNonce, sharedKey))
.collect(Collectors.toList());
}

4. Restful API

4.1 Q2TRestApp

quorum节点和tessera之间的数据交换

api method 功能
send post Send private transaction payload
sendRaw post Send private transaction payload
sendsignedtx post Send private raw transaction payload
receive get Submit keys to retrieve payload and decrypt it
receiveRaw get Submit keys to retrieve payload and decrypt it
transaction/{hash} get Returns decrypted payload back to Quorum
transaction/{key} delete Delete single transaction from P2PRestApp node
upcheck get Node is up?
version get Node’s version
storeraw post Store raw private transaction payload

4.2 ThirdPartyRestApp

api method 功能
key get Fetch local public keys managed by the enclave
partyinfo/key get Fetch network/peer public keys
storeraw post Store raw private transaction payload

4.3 P2PRestApp

tessera节点之间的数据交换

api method 功能
resend post Resend transactions for given key or message hash/recipient
push post Transmit encrypted payload between P2PRestApp Nodes
partyinfo post Request public key/url of other nodes
partyinfo get Fetch network/peer information
partyinfo/validate post validate network/peer

4.4 EnclaveApplication

提供main方法,可以独立启动成web服务提供Restful API,也可以走内部调用(默认)

api method 功能
ping get 获取Encalve服务状态
default get 获取默认的公钥(第一个)
forwarding get 获取要转发的公钥列表
public get 获取公钥
encrypt post 加密playload
encrypt/raw post 加密rawplayload
encrypt/toraw post playload转换成rawplayload
unencrypt post 解密Payload
addRecipient post 添加收件人

5. 一些核心接口

App、Enclave相关的类图:

在这里插入图片描述

某些接口手工加了成员变量

com.quorum.tessera.server.TesseraServer

public interface TesseraServer { 

void start() throws Exception;
void stop() throws Exception;
}

com.quorum.tessera.key.generation.KeyGenerator

public interface KeyGenerator { 

ConfigKeyPair generate(String filename, ArgonOptions encryptionOptions, KeyVaultOptions keyVaultOptions);
}

com.quorum.tessera.encryption.Encryptor

/** * The API provided to the application that all implementation of this API * module should extend * <p> * Provides all function relating to encrypting and decrypting messages * using public/private and symmetric keys. */
public interface Encryptor { 

/** * Compute the shared key from a public/private key combination * The keys must be from different keysets. * Providing the public key for the corresponding private key (and vice versa) results in an error * <p> * The shared key for a public/private key combo is the same as if the private/public corresponding keys * were provided. * i.e. public1/private2 == private1/public2 * * @param publicKey A public key from the first keyset * @param privateKey A private key from the second keyset * @return The shared key for this key pair. */
SharedKey computeSharedKey(PublicKey publicKey, PrivateKey privateKey);
/** * Encrypt a payload directly using the given public/private key pair for the sender/recipient * * @param message The payload to be encrypted * @param nonce A unique nonce for this public/private pair * @param publicKey The key from either sender or recipient * @param privateKey The other key from either sender or recipient * @return The encrypted payload */
byte[] seal(byte[] message, Nonce nonce, PublicKey publicKey, PrivateKey privateKey);
/** * Decrypt a payload directly using the given public/private key pair for the sender/recipient * * @param cipherText The payload to be encrypted * @param nonce A unique nonce for this public/private pair * @param publicKey The key from either sender or recipient * @param privateKey The other key from either sender or recipient * @return The encrypted payload */
byte[] open(byte[] cipherText, Nonce nonce, PublicKey publicKey, PrivateKey privateKey);
/** * Encrypt a payload using the given public/private key pair for the sender/recipient * * @param message The payload to be encrypted * @param nonce A unique nonce for this public/private pair * @param sharedKey The shared key between the sender and recipient of the payload * @return The encrypted payload */
byte[] sealAfterPrecomputation(byte[] message, Nonce nonce, SharedKey sharedKey);
default byte[] sealAfterPrecomputation(byte[] message, Nonce nonce, MasterKey masterKey) { 

SharedKey sharedKey = SharedKey.from(masterKey.getKeyBytes());
return sealAfterPrecomputation(message, nonce, sharedKey);
}
/** * Decrypts a payload using the shared key between the sender and recipient * * @param cipherText The encrypted payload * @param nonce The nonce that was used to encrypt this payload * @param sharedKey The shared key for the sender and recipient * @return The decrypted payload */
byte[] openAfterPrecomputation(byte[] cipherText, Nonce nonce, SharedKey sharedKey);
/** * Generates a new random nonce of the correct size * * @return a {@link Nonce} containing random data to be used as a nonce */
Nonce randomNonce();
/** * Generates a new public and private keypair * * @return A pair of public and private keys */
KeyPair generateNewKeys();
/** * Creates a single standalone key * * @return The randomly generated key */
SharedKey createSingleKey();
/** * Create a randomly generated {@link MasterKey} * * @return a random {@link MasterKey} */
default MasterKey createMasterKey() { 

SharedKey sharedKey = createSingleKey();
return MasterKey.from(sharedKey.getKeyBytes());
}
/** * Decrypts a payload using the given {@link MasterKey} * * @param cipherText the ciphertext to decrypt * @param cipherTextNonce the nonce that was used to encrypt the payload * @param masterKey the key used to encrypt the payload * @return the decrypted payload * @see Encryptor#openAfterPrecomputation(byte[], Nonce, SharedKey) */
default byte[] openAfterPrecomputation(byte[] cipherText, Nonce cipherTextNonce, MasterKey masterKey) { 

SharedKey sharedKey = SharedKey.from(masterKey.getKeyBytes());
return openAfterPrecomputation(cipherText, cipherTextNonce, sharedKey);
}
}

com.quorum.tessera.enclave.Enclave

/** * An {@link Enclave} provides encryption/decryption functions and keeps hold * of all the nodes private keys so the do not leak into other services. */
public interface Enclave extends Service { 

private final Encryptor encryptor;
private final KeyManager keyManager;
/** * Retrieves the public key to use if no key is specified for an operation * There is no guarantee this key remains the same between runs of the Enclave. * * @return the public key that has been assigned as the default */
PublicKey defaultPublicKey();
/** * Returns a set of public keys that should be included as recipients to * all transactions produced by this node. The keys are not be managed by * this node. * * @return the set of public keys to be added to transactions */
Set<PublicKey> getForwardingKeys();
/** * Returns all the public keys that are managed by this Enclave. * * @return all public keys managed by this Enclave */
Set<PublicKey> getPublicKeys();
/** * Encrypts a message using the specified sender and a list of recipients. * Returns a {@link EncodedPayload} which contains all the encrypted * information, including the recipients and their encrypted master keys. * * @param message the message to be encrypted * @param senderPublicKey the public key which this enclave manages * @param recipientPublicKeys the recipients to encrypt this message for * @return the encrypted information, represented by an {@link EncodedPayload} */
EncodedPayload encryptPayload(byte[] message, PublicKey senderPublicKey, List<PublicKey> recipientPublicKeys);
/** * Decrypts a {@link RawTransaction} so that it can be re-encrypted into a * {@link EncodedPayload} with the given recipient list * * @param rawTransaction the transactiopn to decrypt and re-encrypt with recipients * @param recipientPublicKeys the recipients to encrypt the transaction for * @return the encrypted information, represented by an {@link EncodedPayload} */
EncodedPayload encryptPayload(RawTransaction rawTransaction, List<PublicKey> recipientPublicKeys);
/** * Encrypt a payload without any recipients that can be retrieved later. * The payload is encrypted using the private key that is related to the * given public key. * * @param message the message to be encrypted * @param sender the sender's public key to encrypt the transaction with * @return the encrypted transaction */
RawTransaction encryptRawPayload(byte[] message, PublicKey sender);
/** * Decrypt a transaction and fetch the original message using the given * public key. Throws an {@link com.quorum.tessera.nacl.NaclException} if * the provided public key OR one of the Enclave's managed keys cannot be * used to decrypt the payload * * @param payload the encrypted payload * @param providedKey the key to use for decryption, if the payload wasn't sent by this Enclave * @return the original, decrypted message */
byte[] unencryptTransaction(EncodedPayload payload, PublicKey providedKey);
/** * Creates a new recipient box for the payload, for which we must be the originator. * At least one recipient must already be available to be able to decrypt the master key. * * @param payload the payload to add a recipient to * @param recipientKey the new recipient key to add */
byte[] createNewRecipientBox(EncodedPayload payload, PublicKey recipientKey);
@Override
default void start() { 

}
@Override
default void stop() { 

}
}

com.quorum.tessera.context.RuntimeContext

public interface RuntimeContext { 

List<KeyPair> getKeys();
KeyEncryptor getKeyEncryptor();
List<PublicKey> getAlwaysSendTo();
List<URI> getPeers();
Client getP2pClient();
boolean isRemoteKeyValidation();
URI getP2pServerUri();
static RuntimeContext getInstance() { 

return ContextHolder.INSTANCE.getContext().get();
}
boolean isDisablePeerDiscovery();
default Set<PublicKey> getPublicKeys() { 

return getKeys().stream().map(KeyPair::getPublicKey).collect(Collectors.toSet());
}
boolean isUseWhiteList();
}

com.quorum.tessera.partyinfo.PartyInfoService

public interface PartyInfoService { 

/** * Request PartyInfo data from all remote nodes that this node is aware of * * @return PartyInfo object */
PartyInfo getPartyInfo();
/** * Update the PartyInfo data store with the provided encoded data.This can happen when endpoint /partyinfo is * triggered, or by a response from this node hitting another node /partyinfo endpoint * * @param partyInfo * @return updated PartyInfo object */
PartyInfo updatePartyInfo(PartyInfo partyInfo);
// Set<String> getUrlsForKey(PublicKey key);
PartyInfo removeRecipient(String uri);
/** * Formats, encodes and publishes encrypted messages using the target public key as the identifier, instead of the * URL * * @param payload the pre-formatted payload object (i.e. with all recipients still present) * @param recipientKey the target public key to publish the payload to * @throws com.quorum.tessera.encryption.KeyNotFoundException if the target public key is not known */
void publishPayload(EncodedPayload payload, PublicKey recipientKey);
// TODO: Added as lifecycle call once RuntimeContext has been created.
void populateStore();
}

com.quorum.tessera.transaction.TransactionManager

	public interface TransactionManager { 

private final PayloadEncoder payloadEncoder;
private final Base64Decoder base64Decoder;
private final EncryptedTransactionDAO encryptedTransactionDAO;
private final EncryptedRawTransactionDAO encryptedRawTransactionDAO;
private final PartyInfoService partyInfoService;
private final Enclave enclave;
private final ResendManager resendManager;
private final MessageHashFactory messageHashFactory = MessageHashFactory.create();
private int resendFetchSize;
SendResponse send(SendRequest sendRequest);
SendResponse sendSignedTransaction(SendSignedRequest sendRequest);
void delete(DeleteRequest request);
ResendResponse resend(ResendRequest request);
MessageHash storePayload(byte[] toByteArray);
ReceiveResponse receive(ReceiveRequest request);
StoreRawResponse store(StoreRawRequest storeRequest);
}

com.quorum.tessera.config.AppType

public enum AppType { 

P2P(CommunicationType.REST),
Q2T(CommunicationType.REST),
THIRD_PARTY(CommunicationType.REST),
ENCLAVE(CommunicationType.REST),
ADMIN(CommunicationType.REST);
}

6. 主要配置文件

tessera-config.json 示例

 { 

"useWhiteList": false,
"jdbc": { 

"username": "sa",
"password": "",
"url": "jdbc:h2:test/db;MODE=Oracle;TRACE_LEVEL_SYSTEM_OUT=0",
"autoCreateTables": true
},
"serverConfigs":[
{ 

"app":"ThirdParty",
"enabled": true,
"serverAddress": "http://$$(hostname -i):9080",
"communicationType" : "REST"
},
{ 

"app":"Q2T",
"enabled": true,
"serverAddress": "unix:$${DDIR}/tm.ipc",
"communicationType" : "REST"
},
{ 

"app":"P2P",
"enabled": true,
"serverAddress": "http://$$(hostname -i):9000",
"sslConfig": { 

"tls": "OFF"
},
"communicationType" : "REST"
}
],
"peer": [
{ 

"url": "http://txmanager1:9000"
},
{ 

"url": "http://txmanager2:9000"
},
{ 

"url": "http://txmanager3:9000"
},
{ 

"url": "http://txmanager4:9000"
},
{ 

"url": "http://txmanager5:9000"
},
{ 

"url": "http://txmanager6:9000"
},
{ 

"url": "http://txmanager7:9000"
}
],
"keys": { 

"passwords": [],
"keyData": [
{ 

"config": "tm.key",
"publicKey": "tm.pub"
}
]
},
"alwaysSendTo": []
}

tessera-dist/tessera-app/src/main/resources/tessera-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/tessera-core-spring.xml" />
<import resource="classpath:/tessera-partyinfo-spring.xml" />
</beans>

tessera-core/src/main/resources/tessera-core-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<tx:annotation-driven transaction-manager="jpaTransactionManager"/>
<context:component-scan base-package="com.quorum.tessera"/>
<bean id="enclaveFactory" class="com.quorum.tessera.enclave.EnclaveFactory" factory-method="create" />
<bean id="enclave" factory-bean="enclaveFactory" factory-method="create">
<constructor-arg ref="config" />
</bean>
<bean class="com.quorum.tessera.service.ServiceContainer">
<constructor-arg ref="enclave" />
</bean>
<bean id="transactionManager" class="com.quorum.tessera.transaction.TransactionManagerImpl">
<constructor-arg ref="encryptedTransactionDAO" />
<constructor-arg ref="enclave" />
<constructor-arg ref="encryptedRawTransactionDAO" />
<constructor-arg ref="resendManager" />
<constructor-arg ref="partyInfoService" />
<constructor-arg value="#{config.getJdbcConfig().getFetchSize() > 0 ? config.getJdbcConfig().getFetchSize() : 1000}"/>
</bean>
<bean id="cliDelegate" class="com.quorum.tessera.cli.CliDelegate" factory-method="instance"/>
<bean id="config" factory-bean="cliDelegate" factory-method="getConfig"/>
<bean name="encryptedTransactionDAO" class="com.quorum.tessera.data.EncryptedTransactionDAOImpl"/>
<bean name="encryptedRawTransactionDAO" class="com.quorum.tessera.data.EncryptedRawTransactionDAOImpl"/>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="#{ config.getJdbcConfig().getUrl() }" />
<property name="username" value="#{ config.getJdbcConfig().getUsername() }" />
<property name="password" value="#{ resolver.resolve(config.getJdbcConfig().getPassword()) }" />
</bean>
<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="tessera"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" />
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="eclipselink.weaving">false</prop>
<prop key="eclipselink.session-name">tessera</prop>
<prop key="eclipselink.logging.logger">org.eclipse.persistence.logging.slf4j.SLF4JLogger</prop>
<prop key="eclipselink.logging.session">false</prop>
<prop key="javax.persistence.schema-generation.database.action">#{config.getJdbcConfig().isAutoCreateTables() ? 'create' : 'none'}</prop>
</props>
</property>
</bean>
<bean id="resolver" class="com.quorum.tessera.config.util.EncryptedStringResolver"/>
</beans>

tessera-partyinfo/src/main/resources/tessera-partyinfo-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="p2pClientFactory" class="com.quorum.tessera.partyinfo.P2pClientFactory" factory-method="newFactory">
<constructor-arg ref="config" />
</bean>
<bean id="p2pClient" factory-bean="p2pClientFactory" factory-method="create">
<constructor-arg ref="config"/>
</bean>
<bean id="resendClientFactory" class="com.quorum.tessera.sync.ResendClientFactory" factory-method="newFactory">
<constructor-arg ref="config"/>
</bean>
<bean id="resendClient" factory-bean="resendClientFactory" factory-method="create">
<constructor-arg ref="config"/>
</bean>
<bean id="payloadPublisherFactory" class="com.quorum.tessera.partyinfo.PayloadPublisherFactory" factory-method="newFactory">
<constructor-arg ref="config" />
</bean>
<bean id="payloadPublisher" class="com.quorum.tessera.partyinfo.PayloadPublisher" factory-bean="payloadPublisherFactory" factory-method="create">
<constructor-arg ref="config" />
</bean>
<!-- Party Info management -->
<bean name="partyInfoStore" class="com.quorum.tessera.partyinfo.PartyInfoStore">
<constructor-arg value="#{config.getP2PServerConfig().getServerUri()}"/>
</bean>
<bean name="partyInfoService" class="com.quorum.tessera.partyinfo.PartyInfoServiceImpl">
<constructor-arg ref="partyInfoStore"/>
<constructor-arg ref="enclave"/>
<constructor-arg ref="payloadPublisher"/>
</bean>
<bean name="partyInfoPoller" class="com.quorum.tessera.partyinfo.PartyInfoPoller">
<constructor-arg ref="partyInfoService"/>
<constructor-arg ref="p2pClient"/>
</bean>
<bean name="propertyHelper" class="com.quorum.tessera.config.util.IntervalPropertyHelper">
<constructor-arg value="#{config.getP2PServerConfig().getProperties()}"/>
</bean>
<bean name="partyInfoPollExecutor" class="com.quorum.tessera.threading.TesseraScheduledExecutor">
<constructor-arg>
<bean class="java.util.concurrent.Executors" factory-method="newSingleThreadScheduledExecutor"/>
</constructor-arg>
<constructor-arg ref="partyInfoPoller"/>
<constructor-arg value="#{propertyHelper.partyInfoInterval()}"/>
<constructor-arg value="5000"/>
</bean>
<bean id="resendManager" class="com.quorum.tessera.partyinfo.ResendManagerImpl">
<constructor-arg ref="encryptedTransactionDAO" />
<constructor-arg ref="enclave" />
</bean>
<!-- Local key sync -->
<bean name="enclaveKeySynchroniser" class="com.quorum.tessera.partyinfo.EnclaveKeySynchroniser">
<constructor-arg ref="enclave" />
<constructor-arg ref="partyInfoStore" />
<constructor-arg value="#{config.getP2PServerConfig().getServerUri()}" />
</bean>
<bean name="enclaveKeySynchroniserExecutor" class="com.quorum.tessera.threading.TesseraScheduledExecutor">
<constructor-arg>
<bean class="java.util.concurrent.Executors" factory-method="newSingleThreadScheduledExecutor"/>
</constructor-arg>
<constructor-arg ref="enclaveKeySynchroniser"/>
<constructor-arg value="#{propertyHelper.enclaveKeySyncInterval()}"/>
<constructor-arg value="5000"/>
</bean>
<!-- Node synchronization management-->
<beans profile="enable-sync-poller">
<bean name="resendPartyStore" class="com.quorum.tessera.sync.ResendPartyStoreImpl"/>
<bean name="transactionRequester" class="com.quorum.tessera.sync.TransactionRequesterImpl">
<constructor-arg ref="enclave" />
<constructor-arg ref="resendClient" />
</bean>
<bean name="syncPoller" class="com.quorum.tessera.sync.SyncPoller">
<constructor-arg ref="resendPartyStore" />
<constructor-arg ref="transactionRequester" />
<constructor-arg ref="partyInfoService"/>
<constructor-arg ref="p2pClient"/>
</bean>
<bean class="com.quorum.tessera.threading.TesseraScheduledExecutor">
<constructor-arg>
<bean class="java.util.concurrent.Executors" factory-method="newSingleThreadScheduledExecutor"/>
</constructor-arg>
<constructor-arg ref="syncPoller"/>
<constructor-arg value="#{propertyHelper.syncInterval()}"/>
<constructor-arg value="5000"/>
</bean>
</beans>
</beans>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/138934.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • pytest的使用_实例方法只能用实例来调用

    pytest的使用_实例方法只能用实例来调用Pytest执行用例规则Pytest在命令行中支持多种方式来运行和选择测试用例1.对某个目录下所有的用例pytest2.对模块中进行测试pytesttest_mod.py3.对文件夹进行

  • MMC 卡驱动分析[通俗易懂]

    MMC 卡驱动分析[通俗易懂]最近花时间研究了一下MMC卡驱动程序,开始在网上找了很多关于MMC卡驱动的分析文章,但大都是在描述各个层,这对于初学者来讲帮助并不大,所以我就打算把自己的理解写下来,希望对大家有用。个人觉得理解LINUX内核当中MMC/SD卡驱动程序构架是学习MMC卡驱动程序的重点,只有理解了它的基本框架或流程才能真正理解一个块设备驱动程序的写法,同时才能真正理解LINUX设备驱动模型是如

  • Linux配置IP地址的方法

    Linux配置IP地址的方法ifconfig命令临时配置IP地址ifconfig命令:查看与配置网络状态的命令//查看当前网络状态#ifconfig//配置网卡的临时生效的IP地址#ifconfigeth0192.168.0.200netmask255.255.255.0//配置网关routeadddefaultgw192.168.0.1setup工具永久配置IP地址RedHat专有图形化工具

  • git拉取代码冲突了怎么解决_github拉取代码慢

    git拉取代码冲突了怎么解决_github拉取代码慢问题描述在idea通过git从develop分支拉取最新代码时,又遇到了git冲突,特此记录一下原因分析:大部分原因都是其他同事更改了某些文件然后本地也更改了同样的文件导致冲突,所以每天上班先拉取一下最新代码,这样会大大减少冲突发生的可能(别问我怎么知道的)解决方案:如下图所示:我们点击merge去合并即可,解决冲突,不建议直接选择acceptyours或者accepttheirs会导致代码覆盖…

    2022年10月20日
  • mybatis缓存配置

    mybatis缓存配置mybatis的缓存有三种方式:1、一级缓存(基于SqlSession会话级别的;2、二级缓存(基于nameSpace级别的,范围比以及缓存更广);3、第三方缓存;mybatis缓存使示意图:一、一级缓存说明:其中一级缓存是mybatis默认使用的缓存,无需手动配置,二级缓存需要手动配置;一级缓存失效条件1)sqlSession不同,由于一级缓存是基于sqlSession级别的,所以当使用不同sq…

  • tree命令详解

    tree命令详解命令:tree命令说明:以树状格式列出目录的内容,查看文件系统的结构命令用法:tree[选项]…[文件]…参数说明:参数参数说明备注-a打印所有文件,包括隐藏文件、目录-C在文件和目录清单上加上色彩,便于区分文件类型-d仅列出目录名称,而非内容-D列出文件或目录更改时间-L目录树的最大显示深度-p打印结构同时打印文件权限-l跟随目录的符号链接,就像它们是目录一样。避免了导致递归循环的链接-f打印每个

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号