【quorum源码】quorum tessera源码剖析

article/2025/9/12 8:08:49

目录

    • 概述
    • 1. 项目结构
    • 2. 数据库结构
    • 3. 主要流程
        • 3.1 服务启动
        • 3.2 交易处理
        • 3.3 加密交易
    • 4. Restful API
        • 4.1 Q2TRestApp
        • 4.2 ThirdPartyRestApp
        • 4.3 P2PRestApp
        • 4.4 EnclaveApplication
    • 5. 一些核心接口
        • App、Enclave相关的类图:
        • com.quorum.tessera.server.TesseraServer
        • com.quorum.tessera.key.generation.KeyGenerator
        • com.quorum.tessera.encryption.Encryptor
        • com.quorum.tessera.enclave.Enclave
        • com.quorum.tessera.context.RuntimeContext
        • com.quorum.tessera.partyinfo.PartyInfoService
        • com.quorum.tessera.transaction.TransactionManager
        • com.quorum.tessera.config.AppType
    • 6. 主要配置文件
        • tessera-config.json 示例
        • tessera-dist/tessera-app/src/main/resources/tessera-spring.xml
        • tessera-core/src/main/resources/tessera-core-spring.xml
        • tessera-partyinfo/src/main/resources/tessera-partyinfo-spring.xml

概述

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之间的数据交换

apimethod功能
sendpostSend private transaction payload
sendRawpostSend private transaction payload
sendsignedtxpostSend private raw transaction payload
receivegetSubmit keys to retrieve payload and decrypt it
receiveRawgetSubmit keys to retrieve payload and decrypt it
transaction/{hash}getReturns decrypted payload back to Quorum
transaction/{key}deleteDelete single transaction from P2PRestApp node
upcheckgetNode is up?
versiongetNode’s version
storerawpostStore raw private transaction payload

4.2 ThirdPartyRestApp

apimethod功能
keygetFetch local public keys managed by the enclave
partyinfo/keygetFetch network/peer public keys
storerawpostStore raw private transaction payload

4.3 P2PRestApp

tessera节点之间的数据交换

apimethod功能
resendpostResend transactions for given key or message hash/recipient
pushpostTransmit encrypted payload between P2PRestApp Nodes
partyinfopostRequest public key/url of other nodes
partyinfogetFetch network/peer information
partyinfo/validatepostvalidate network/peer

4.4 EnclaveApplication

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

apimethod功能
pingget获取Encalve服务状态
defaultget获取默认的公钥(第一个)
forwardingget获取要转发的公钥列表
publicget获取公钥
encryptpost加密playload
encrypt/rawpost加密rawplayload
encrypt/torawpostplayload转换成rawplayload
unencryptpost解密Payload
addRecipientpost添加收件人

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);@Overridedefault void start() {}@Overridedefault 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.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://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>

http://chatgpt.dhexx.cn/article/09u3271p.shtml

相关文章

Quorum NWR算法

假如我们遇到这样一种事情&#xff1a;你开发实现了一套 AP 型的分布式系统&#xff0c;实现了最终一致性。业务也接入了&#xff0c;运行正常&#xff0c;一起看起来都那么美好。可是&#xff0c;突然有同事说&#xff0c;我们要拉这几个业务的数据做实时分析&#xff0c;希望…

paxosquorum

注&#xff1a; 这里谈论的2PC不同于事务中的2PC&#xff0c;而是专门为了同步和高可用改过的2PC协议 问题&#xff1a; 寻求一种能够保证&#xff0c;在给定多台计算机&#xff0c;并且他们之间由网络相互连通&#xff0c;中间的数据没有拜占庭将军问题(数据不会被伪造)的前…

分布式共识算法随笔 —— 从 Quorum 到 Paxos

分布式共识算法随笔 —— 从 Quorum 到 Paxos 概览: 为什么需要共识算法&#xff1f; 昨夜西风凋碧树&#xff0c;独上高楼&#xff0c;望尽天涯路 复制(Replication) 是一种通过将同一份数据在复制在多个服务器上来提高系统可用性和扩展写吞吐的策略, 。常见的复制策略有主从…

Quorum工作原理

文章目录 1. 概述2. 逻辑架构2.1 Quorum Node2.2 Constellation&#xff08;星座&#xff09;2.3 Tessera&#xff08;特赛拉&#xff09;2.4 Transaction Manager2.5 Enclave 3. 交易&#xff08;事务&#xff09;处理3.1 公开交易3.2 隐私交易3.3 交易处理3.4 隐私交易流程&a…

Quorum共识简析

背景 区块链共识是指多个节点或代理在给定的时间点就区块链状态达成一致的能力。当涉及区块链上分散记录保存和验证的核心功能时&#xff0c;单独依靠信任来确保添加到账本的信息是正确的可能会存在问题。因为没有中央实体来进行仲裁&#xff0c;这种问题在去中心化网络中更为…

Quorum区块链原理及其概念

Quorum概述 Quorum是由摩根大通研发的企业级区块链&#xff0c;用于解决金融或满足于企业需求的行业的需求的平台[56]。Quorum是基于以太坊扩展研发的一种联盟链&#xff0c;适用于对交易效率和吞吐量比较高的企业应用。Quorum作为以太坊的许可实施方案&#xff0c;对以太坊设…

Quorum 机制(分布式系统)

Quorum 机制&#xff0c;是一种分布式系统中常用的&#xff0c;用来保证数据冗余和最终一致性的投票算法&#xff0c;其主要数学思想来源于鸽巢原理。 基于Quorum投票的冗余控制算法 在有冗余数据的分布式存储系统当中&#xff0c;冗余数据对象会在不同的机器之间存放多份拷贝…

xgboost的原理,损失函数,优化,

不经感叹大佬真多&#xff0c;本文转自https://www.jianshu.com/p/7467e616f227 xgboostd多颗树的损失子树cart树&#xff0c;并且叶子节点为分数&#xff0c;不是类别&#xff0c;所有多棵树损失和容易优化&#xff0c;速度快分步提升&#xff0c;先优化一棵树&#xff0c;后面…

XGBoost简介

本文据此对XGBoost的原理做简单的介绍... XGBoost[1]是2014年2月诞生的专注于梯度提升算法的机器学习函数库&#xff0c;此函数库因其优良的学习效果以及高效的训练速度而获得广泛的关注。仅在2015年&#xff0c;在Kaggle[2]竞赛中获胜的29个算法中&#xff0c;有17个使用了XGB…

XGBoost原理及应用

XGBOST原理 XGBoost是使用梯度提升框架实现的高效、灵活、可移植的机器学习库&#xff0c;全称是EXtreme Gradient Boosting. XGBoost算法原理 其实算法的原理就是在一颗决策树的基础上不断地加树&#xff0c;比如在n-1颗树地基础上加一棵树变成n颗树的同时算法的精确率不断…

XGBoost原理与实例分析

这几天一直在研究XGboost的基本原理与代码调参&#xff0c;其原理是在GBDT的基础上进行优化&#xff0c;但也有很多的不同之处&#xff1b;所以自己准备更新两篇博客分为XGBoost原理与实例和XGBoost实战与调参优化来巩固这方面的知识。 一、XGBoost原理分析 在机器学习的问题…

XGBoost原理

前言 之前接触并实现过Adaboost和Random Forest。作为去年开始很火爆的&#xff0c;对结构化数据效果极佳的XGBoost&#xff0c;当然也需要了解一下了。下面将分段叙述XGBoost原理&#xff0c;以及与GBDT的关系等等内容。 ①、XGBoost vs GBDT 说到XGBoost&#xff0c;不得不说…

XGBoost算法原理以及实现

想问&#xff1a;在CSDN如何编辑数学公式呢&#xff1f; XGBoost算法是由GBDT算法演变出来的&#xff0c;GBDT算法在求解最优化问题的时候应用了一阶导技术&#xff0c;而XGBoost则使用损失函数的一阶导和二阶导&#xff0c;不但如此&#xff0c; 还可以自己定义损失函数&…

XGBoost原理介绍------个人理解版

本人第一次写博客&#xff0c;这是篇算法总结的文章&#xff0c;希望能对大家的学习有所帮助。有什么错误之处&#xff0c;还望留言指出&#xff0c;希望能与大家一起进步。 XGBoost全名叫&#xff08;eXtreme Gradient Boosting&#xff09;极端梯度提升&#xff0c;经常被用…

XGBoost原理及目标函数推导详解

前言 XGBoost&#xff08;eXtreme Gradient Boosting&#xff09;全名叫极端梯度提升&#xff0c;XGBoost是集成学习方法的王牌&#xff0c;在Kaggle及工业界都有广泛的应用并取得了较好的成绩&#xff0c;本文较详细的介绍了XGBoost的算法原理及目标函数公式推导。 一、XGBoo…

机器学习——XGboost原理及python实现

XGboost原理及实战 原理1 xgb是什么1.1 CART 回归树1.2 应用1.3 目标函数 2 xgb数学推导2.1 回归树2.2 加法模型2.3 前向分步算法2.4 目标函数2.5 正则项处理2.6 损失函数的处理 3 确定树的结构3.1 精确贪心法 4 具体算法流程&#xff1a;5 优化思路&#xff1a;5.1 压缩特征数…

XGBoost简单介绍

1. 概述 XGBoost本身的核心是基于梯度提升树实现的集成算法&#xff0c;整体来说可以有三个核心部分&#xff1a;集成算法本身&#xff0c;用于集成的弱评估器&#xff0c;以及应用中的其他过程。 1.1 提升集成算法&#xff1a; XGBoost的基础是梯度提升算法&#xff0c;因此…

XGBoost算法原理及基础知识

XGBoost原理——理论基础、公式推导、单机实现 前言一.简述XGBoost1.1算法类型&#xff1a;集成学习、监督学习1.2应用场景&#xff1a;回归、分类、排序1.3模型原理&#xff1a;串行方法、加法模型 二.集成学习及主要方法2.1Boosting 串行方法2.2Bagging 并行方法2.3Stacking …

xgboost算法原理

xgboost算法原理 1.xgboost的介绍 xgboost的全称&#xff08;extreme gradient boosting)极限梯度提升&#xff0c;经常被用在一些比赛中&#xff0c;其效果显著。它是大规模并行boosted tree 的工具&#xff0c;是目前最快最好的开源Boosted tree工具包。xgboost所应用的算法…

Xgboost算法之原理+代码

https://blog.csdn.net/kwame211/article/details/81098025 这里有一套系统的XGBoost学习方法&#xff0c;结合学习吧&#xff01; 1. XGBoost简介 xgboost一般和sklearn一起使用&#xff0c;但是由于sklearn中没有集成xgboost&#xff0c;所以才需要单独下载安装。xgboost是…