Java/Kotlin SDK Node client and domain.
we-node-client allows you to create and use client nodes with flexible settings through wrappers of NodeBlockingServiceFactory.
Our primary goals are:
- Provide flexibility to use the client in the client code by making abstractions for the possibility of overriding.
- Providing basic functionality for the correct and stable operation of the clients. For example:
- RateLimitingServiceFactory - a wrapper for limiting requests to the node based on the UTX pool load and the provided settings.
- LoadBalancingServiceFactory - a wrapper for HTTP load balancing when working with more than one WE blockchain node.
- Provide the ability to choose from different types of transport to communicate with Blockchain Nodes: GRPC(GrpcNodeServiceFactory) or HTTP(FeignNodeServiceFactory).
There are several modules in we-node-client. Here is a quick overview:
The module responsible for working with atomic transactions (120). The main element of which is AtomicAwareNodeBlockingServiceFactory.
AtomicAwareNodeBlockingServiceFactory - a wrapper which accepts NodeBlockingServiceFactory in its constructor. The main task of this wrapper is:
- Intercepting the broadcast of transactions and collecting them in the AtomicContext instead;
- Building resulting AtomicTx with all the collected transactions;
- Signing and broadcasting atomic transaction;
Interfaces for working with Node API in a blocking way and client wrappers.
TxService, ContractService, AddressService, NodeInfoService, PrivacyService, BlocksService, NodeUtilsService.
- RateLimitingServiceFactory - wrapper for a single HTTP client that limits the load on the WE Blockchain Node;
- CachingNodeBlockingServiceFactory - wrapper for efficient use of the node by storing a temporary cache.
- LoadBalancingServiceFactory - wrapper for load balancing between nodes;
Wraps specific services that work with transactions(BlockService, TxService) and privacy(PrivacyService). It is done in the following way:
-
BlockService: When receiving one(
block At Height({height})
) or several(blockSequence({fromHeight}, {toHeight})
) blocks - all aligned transactions from the received blocks will be cached. -
TxService: When a transaction is received (
txInfo({txId})
), if it was previously cached, it will be returned from the cache, or added to it, if it is missing. -
PrivacyService: When receiving policy item info (
info({policyItemRequest})
) caches the successful response.
Domain models for Node.
Exceptions thrown by node clients common for all implementations.
Each transport implementation (GRPC/HTTP) should provide mapping to these errors. For example this is how it is done in FeignNodeErrorMapper.
Contains the implementation of a node client using a GRPC protocol.
Kotlin:
val grpcNodeServiceFactory: GrpcNodeServiceFactory = GrpcNodeServiceFactoryFactory.createClient(
grpcProperties = GrpcNodeClientParams(
address = "node-address",
port = 8080,
keepAliveTime = 5000,
keepAliveWithoutCalls = true,
)
)
Java:
GrpcNodeServiceFactory grpcNodeServiceFactory =
GrpcNodeServiceFactoryFactory.createClient(
new GrpcNodeClientParams("node-address", 8080, 5000L, true),
null
);
Contains implementation of a node client using the HTTP protocol.
There can different implementations for this type of transport, at the moment only Feign implementation is available (we-node-client-feign-client).
More settings in FeignNodeClientParams.
Kotlin:
val feignNodeBlockingServiceFactory = FeignNodeServiceFactory(
params = FeignNodeClientParams(
url = "https://localhost:8080",
xApiKey = "xApiKey",
)
)
Java:
FeignNodeServiceFactory feignNodeBlockingServiceFactory = new FeignNodeServiceFactory(
new FeignNodeClientParams(
"https://locaclhost:8080",
"xApiKey"
)
);
Module for mapping domain objects to DTO and vice versa.
Module for creating pre-filled test objects. Consists of static methods in the TestDataFactory.
Kotlin:
val createContractTx: CreateContractTx = TestDataFactory.createContractTx()
Interface fo signing transactions before broadcasting them to WE Node. Implementations should populate SignRequest with ID and proofs in order to create a signed Tx.
Implementation that signs transactions using WE Node REST API with key pairs stored in WE Node KeyStore.
Kotlin:
// creating NodeBlockingServiceFactory for getting TxService
val nodeBlockingServiceFactory = FeignNodeServiceFactory(FeignNodeClientParams("url"))
// creating TxService for TxSigner
val txService: TxService = nodeBlockingServiceFactory.txService()
// setting credentials
val credentials = Credentials(
senderAddress = "senderAddress".base58Address,
password = "password".password,
)
// creating TxSigner with credentials
val txSigner: TxSigner = TxServiceTxSignerFactory(txService = txService).withCredentials(credentials = credentials)
// method sign() will return signed Tx
txSigner.sign(TestDataFactory.createContractSignRequest())
Java:
// creating NodeBlockingServiceFactory for getting TxService
NodeServiceFactory nodeBlockingServiceFactory = new FeignNodeServiceFactory(new FeignNodeClientParams("url"));
// creating TxService for TxSigner
TxService txService = nodeBlockingServiceFactory.txService();
// setting credentials
Credentials credentials = new Credentials(
"senderAddress".base58Address,
"password".password
);
// creating TxSigner with credentials
TxSigner txSigner = new TxServiceTxSignerFactory(txService).withCredentials(credentials);
// method sign() will return signed Tx
txSigner.sign(TestDataFactory.createContractSignRequest());
Gradle:
implementation("com.wavesenterprise:we-node-client-feign-client:$version")
implementation("com.wavesenterprise:we-node-client-grpc-client:$version")
Maven:
<dependency>
<groupId>com.wavesenterprise</groupId>
<artifactId>we-node-client-feign-client</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.wavesenterprise</groupId>
<artifactId>we-node-client-grpc-client</artifactId>
<version>${version}</version>
</dependency>
fun example() {
// create node client with http or grpc connection
val nodeBlockingServiceFactory: NodeBlockingServiceFactory
// get necessary service
val txService: TxService = nodeBlockingServiceFactory.txService()
// use service (API of the interfaces matches the api of the node)
val txInfo: TxInfo = txService.txInfo({txId})
}
public void example() {
// create node client with http or grpc connection
NodeBlockingServiceFactory nodeBlockingServiceFactory;
// get necessary service
TxService txService = nodeBlockingServiceFactory.txService();
// use service (API of the interfaces matches the api of the node)
TxInfo txInfo = txService.txInfo({txId});
}
fun example() {
// default client with http or grpc connection
val nodeBlockingServiceFactory = NodeBlockingServiceFactory
// wrapped rate limiting client
val rateLimitingClient = RateLimitingServiceFactory(
nodeBlockingServiceFactory = nodeBlockingServiceFactory,
rateLimiter = DefaultRateLimiter(
strategy = UtxPoolSizeLimitingStrategy(
txService = nodeBlockingServiceFactory.txService(),
maxUtx = 50,
),
backOff = RandomDelayRateLimitingBackOff(
minWaitMs = 1000,
maxWaitMs = 3000,
maxWaitTotalMs = 10000,
)
)
)
}
public void example() {
// default client with http or grpc connection
NodeBlockingServiceFactory nodeBlockingServiceFactory;
// wrapped rate limiting client
RateLimitingServiceFactory rateLimitingClient = RateLimitingServiceFactory(
nodeBlockingServiceFactory,
new DefaultRateLimiter(
new UtxPoolSizeLimitingStrategy(nodeBlockingServiceFactory.txService(), 50),
new RandomDelayRateLimitingBackOff(1000, 3000, 10000)
)
);
}
fun example() {
// default clients with http or grpc connection
val nodeBlockingServiceFactories: List<NodeBlockingServiceFactory>
// wrapped load balancing client
val lbClient: LoadBalancingServiceFactory = LbServiceFactoryBuilder.builder().build(nodeBlockingServiceFactories)
}
public void example(){
// default clients with http or grpc connection
List<NodeBlockingServiceFactory> nodeBlockingServiceFactories;
// wrapped load balancing client
LoadBalancingServiceFactory lbClient=LbServiceFactoryBuilder.builder().build(nodeBlockingServiceFactories);
}
fun example() {
// default clients with http or grpc connection
val nodeBlockingServiceFactory: NodeBlockingServiceFactory
// wrapped caching client
val cachingClient = CachingNodeBlockingServiceFactoryBuilder.builder().build(nodeBlockingServiceFactory)
}
public void example(){
// default clients with http or grpc connection
List<NodeBlockingServiceFactory> nodeBlockingServiceFactories;
// wrapped caching client
CachingNodeBlockingServiceFactoryBuilder cachingClient = CachingNodeBlockingServiceFactoryBuilder.builder().build(nodeBlockingServiceFactories);
}