Unable to load CordaService - corda

I have a CordaService that looks like this:
#CordaService
class MyService(private val services: AppServiceHub) : SingletonSerializeAsToken() {
private companion object {
private val log = loggerFor<MyService>()
init {
BraidCordaJacksonInit.init()
}
}
init {
println("***** MyService Initializing ****")
}
}
The service has been behaving fine for quite some time. For an unknown reason, it’s no longer being initialised by the runtime.
The node's logs show that the cordapp has been successfully identified and loaded:
I 12:13:58+0100 [main] Main.printBasicNodeInfo - Loaded CorDapps : my-cordapp-0.1, corda-core-3.1-corda {}
If I run the node using NodeDriver:
fun main(args: Array<String>) {
driver(DriverParameters(
isDebug = true,
waitForAllNodesToFinish = true,
startNodesInProcess = true) {
listOf(
startNode(providedName = CordaX500Name("PartyA", "London", "GB"))
).map { it.getOrThrow() }
}
}
... the corda service is correctly initialised:
***** MyService Initializing ****
[INFO ] 12:17:09,934 [driver-pool-thread-0] (AbstractNode.kt:487) internal.Node.installCordaService - Installed io.bluebank.MyService Corda service {}
Is there something specific I need to add to encourage the scanner to locate the class?
Thanks,
Fuzz

This was our fault. Someone had removed the cordapp from ./build.gradle deployNodes configuration!

Related

BeanInstantitationException: Failed to Instantiate Service

I am developing a simple spring boot application in Kotlin. I have one of my service working completely fine. However when i define another service i get this error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'categoryService' defined in file [C:\Users\userName\Documents\Projects\ProjectA\backend\proj\build\classes\kotlin\main\c
om\example\test\category\service\CategoryService.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [c
om.example.test.category.service.CategoryService]: Constructor threw exception; nested exception is java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
at org.springframework.beans.factory
When i remove this service, everything works fine. So adding second service causes this issue.
//Service
#Service
class CategoryService : CategoryServiceInterface {
override fun deleteCategory(userToken: String, categoryId: String): String {
return ""
}
}
//Controller
#RestController
class CategoryController {
#Autowired
lateinit var categoryService: CategoryService
#DeleteMapping("/category")
fun deleteCategory(#RequestHeader(name = "Authorization") token: String, #RequestBody categoryId: String) =
categoryService.deleteCategory(
userToken = token,
categoryId = categoryId
)
//MainApp
#SpringBootApplication
class MainApplication
fun main(args: Array<String>) {
SpringApplication.run(MainApplication::class.java, *args)
}
FirebaseInitializer
#Service
class FirebaseInitializer {
#PostConstruct
fun initialize() {
try {
val serviceAccount = ClassPathResource("serviceaccount.json")
val options = FirebaseOptions
.builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount.inputStream))
.setDatabaseUrl("https://databaseurl.firebaseio.com")
.build()
FirebaseApp.initializeApp(options)
} catch (e: Exception) {
}
}}
I used this article to set up my first service https://medium.com/techwasti/spring-boot-firebase-crud-b0afab27b26e
If i remove this second service, my first service works completely fine. Any help would be greatly appreciated
So i found the problem, If i initialize the firebase with the way mentioned in the article above as a service and using post construct, it gives me the above issues.
I moved my firebase initialize code in my Spring boot application class and everything now works as expected.
#SpringBootApplication
class FoodiesApplication
fun main(args: Array<String>) {
try {
val serviceAccount = ClassPathResource("serviceaccount.json")
val options = FirebaseOptions
.builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount.inputStream))
.setDatabaseUrl("https://databaseurl.firebaseio.com")
.build()
FirebaseApp.initializeApp(options)
} catch (e: Exception) {
}
SpringApplication.run(FoodiesApplication::class.java, *args)
}
Just add #Lazy annotation to bean.

How to setup an execution strategy for Oracle in EF Core 2.2?

I want to set up the execution strategy for Oracle in Entity Framework Core 2.2 by using the DbContext injection. I am using NuGet package Oracle.EntityFrameworkCore for connecting to an Oracle DB.
services.AddDbContext<MyContext>(options =>
{
options.UseOracle(configuration.GetConnectionString("MyConnection"), oracleOptionsAction: oracleOptions =>
{
oracleOptions.ExecutionStrategy(x =>
new MyExecutionStrategy();
});
});
I have created the following execution strategy class for testing purposes. It turns out the class DbExecutionStrategy does not exist in dotnet core:
public class MyExecutionStrategy : DbExecutionStrategy
{
public MyExecutionStrategy() : base(10, TimeSpan.FromSeconds(30))
{
}
protected override bool ShouldRetryOn(Exception exception)
{
return true;
}
}
The class DbExecutionStrategy does not exist in dotnet core only in dotnet. You must implement the abstract class ExecutionStrategy instead.
The custom execution strategy class must be defined in this way:
public class MyExecutionStrategy : ExecutionStrategy
{
public MyExecutionStrategy(ExecutionStrategyDependencies dependencies, int maxRetryCount, TimeSpan maxRetryDelay)
: base(dependencies, maxRetryCount, maxRetryDelay)
{
}
protected override bool ShouldRetryOn(Exception exception)
{
return true;
}
}
Then the dependency injection section:
services.AddDbContext(options =>
{
options.UseOracle(configuration.GetConnectionString("MyConnection"), oracleOptionsAction: oracleOptions =>
{
oracleOptions.ExecutionStrategy(dependencies =>
new MyExecutionStrategy(
dependencies,
retryCount,
retryDelay));
});
});
For Oraсle it is preferable to use the OracleRetryingExecutionStrategy class of the Oracle.EntityFrameworkCore namespace. It already inherits from ExecutionStrategy and has an additional constructor parameter to which you can pass a collection of Oracle error codes to retry.
For example, here is an implementation of some class with default retry options and some Oracle code added for retry:
public class SomeRetryStrategy : OracleRetryingExecutionStrategy
{
private static readonly IList<int> ErrorNumbersToRetry = new List<int>()
{
28, // ORA-00028: Your session has been killed
12570 // ORA-12570: Network Session: Unexpected packet read error
};
public SomeRetryStrategy(ExecutionStrategyDependencies dependencies)
: base(dependencies, DefaultMaxRetryCount, DefaultMaxDelay, ErrorNumbersToRetry)
{
}
}

Corda 4.1 Unable to determine which flow to use

After updating to Corda 4.1 from 3.3, when I run the node with deployNodes I get the following error:
[main] internal.NodeStartupLogging.invoke - Exception during node startup: Unable to determine which flow to use when responding to: com.example.CreateDealFlow.Sender. [com.example.CreateDealFlow.Receiver, com.example.CreateDealFlow.Receiver] are all registered with equal weight. [errorCode=mnl04m, moreInformationAt=https://errors.corda.net/OS/4.1/mnl04m]
there is no any information when I go through URL in error.
My flow looks something like this(I have simplified the code and removed custom logics, just what matters for this case is there)
object CreateDealFlow {
#InitiatingFlow
#StartableByService
class Sender(private val dataHolder: DealDataHolder) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val sender = PartyAndCompany(dataHolder.senderUUID, ourIdentity)
val receiver = PartyAndCompany(dataHolder.receiverUUID, getPartyFromX500String(dataHolder.receiverX500String))
val txBuilder = buildTransaction(sender = sender, receiver = receiver)
txBuilder.verify(serviceHub)
val partiallySignedTransaction = serviceHub.signInitialTransaction(txBuilder)
val parties = partiallySignedTransaction.tx.outputStates.first().participants
val (fullySignedTx, flowSessions) = collectSignaturesFromReceivers(partiallySignedTransaction, parties)
return subFlow(FinalityFlow(fullySignedTx, flowSessions, FinalityFlow.tracker()))
}
#Suspendable
fun buildTransaction(sender: PartyAndCompany, receiver: PartyAndCompany): TransactionBuilder {
}
}
#InitiatedBy(CreateDealFlow.Sender::class)
class Receiver(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
}
}
val txWeJustSigned = subFlow(signTransactionFlow)
return subFlow(ReceiveFinalityFlow(otherPartyFlow, expectedTxId = txWeJustSigned.id))
}
}
}
Resolved by Andranik himself 🙂
The issue was due to having 3 CorDapps (workflows, contracts, workflows-2).
workflows-2 depends on workflows. To do so it was using a compile dependency. When delpoyNodes was run this was building in the workflows code into workflows-2 (a.k.a fat jarring). This then failed at runtime since there were now two CorDapps that contained a flow found in workflows.
To resolve this, cordaCompile was used. This included the workflows module as a compile time dependency but does not build it into the jar. When the node is ran, the flow is loaded from the workflows CorDapp and loaded onto the classpath where workflows-2 can now also access it.

Where to set consensus algorithm in corda?

Where to set consensus algorithm in corda? Answer is expecting in a
technical point of view and if we are working with multiple consensus algorithm then where we switch these algorithms?
As of Corda 3, implementing a custom notary service is still an experimental feature. The APIs for implementing custom notary services may change in the future. Additionally, customising Raft or BFT notaries is not yet fully supported. If you want to write your own Raft notary, you will have to implement a custom database connector (or use a separate database for the notary), and use a custom configuration file.
The first step in implementing a custom notary is to create a notary service class in your CorDapp (i.e. one annotated with #CordaService). The Corda node scans for these service classes and initialises them at srart-up. The custom notary service class should provide a constructor taking an AppServiceHub and a PublicKey:
#CordaService
class MyCustomValidatingNotaryService(override val services: AppServiceHub, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
override val uniquenessProvider = PersistentUniquenessProvider()
override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?> = MyValidatingNotaryFlow(otherPartySession, this)
override fun start() {}
override fun stop() {}
}
The next step is to write the notary service flow. You are free to copy and modify the existing built-in flows such as ValidatingNotaryFlow, NonValidatingNotaryFlow, or implement your own from scratch (following the NotaryFlow.Service template). Below is an example of a custom flow for a validating notary service:
class MyValidatingNotaryFlow(otherSide: FlowSession, service: MyCustomValidatingNotaryService) : NotaryFlow.Service(otherSide, service) {
/**
* The received transaction is checked for contract-validity, for which the caller also has to to reveal the whole
* transaction dependency chain.
*/
#Suspendable
override fun receiveAndVerifyTx(): TransactionParts {
try {
val stx = receiveTransaction()
val notary = stx.notary
checkNotary(notary)
verifySignatures(stx)
resolveAndContractVerify(stx)
val timeWindow: TimeWindow? = if (stx.coreTransaction is WireTransaction) stx.tx.timeWindow else null
return TransactionParts(stx.id, stx.inputs, timeWindow, notary!!)
} catch (e: Exception) {
throw when (e) {
is TransactionVerificationException,
is SignatureException -> NotaryInternalException(NotaryError.TransactionInvalid(e))
else -> e
}
}
}
#Suspendable
private fun receiveTransaction(): SignedTransaction {
return otherSideSession.receive<NotarisationPayload>().unwrap {
val stx = it.signedTransaction
validateRequest(NotarisationRequest(stx.inputs, stx.id), it.requestSignature)
stx
}
}
#Suspendable
private fun resolveAndContractVerify(stx: SignedTransaction) {
subFlow(ResolveTransactionsFlow(stx, otherSideSession))
stx.verify(serviceHub, false)
customVerify(stx)
}
private fun verifySignatures(stx: SignedTransaction) {
val transactionWithSignatures = stx.resolveTransactionWithSignatures(serviceHub)
checkSignatures(transactionWithSignatures)
}
private fun checkSignatures(tx: TransactionWithSignatures) {
try {
tx.verifySignaturesExcept(service.notaryIdentityKey)
} catch (e: SignatureException) {
throw NotaryInternalException(NotaryError.TransactionInvalid(e))
}
}
private fun customVerify(stx: SignedTransaction) {
// Add custom verification logic
}
}
To enable the service, add the following to the node's configuration:
notary : {
validating : true # Set to false if your service is non-validating
custom : true
}

MyBatis Operation Gets Blocked in Spring Boot Async Method

In my project based on Spring Boot 1.3.3, I integrated MyBatis with mybatis-spring-boot-starter 1.1.1 as persistence layer, all CRUD operation seems working fine separately, but the integration tests failed and I found the DB operation gets blocked in asynchronous task.
The test code looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = SapiApplication.class)
#Transactional
public class OrderIntegrationTest {
#Test
public void shouldUpdateOrder() throws InterruptedException{
Order order1 = getOrder1();
orderService.createOrder(order1);
Order order1updated = getOrder1Updated();
orderService.updateOrderAsync(order1updated);
Thread.sleep(1000l);
log.info("find the order!");
Order order1Db = orderService.findOrderById(order1.getOrderId());
log.info("found the order!");
assertEquals("closed", order1Db.getStatus());
}
}
The expected execution order is createOrder() -> updateOrderAsync() -> findOrderById(), but actually the execution order is createOrder() -> updateOrderAsync() started and blocked -> findOrderById() -> updateOrderAsync() continued and ended.
Log:
16:23:04.261 [executor1-1] INFO c.s.api.web.service.OrderServiceImpl - updating order: 2884384
16:23:05.255 [main] INFO c.s.a.w.service.OrderIntegrationTest - find the order!
16:23:05.280 [main] INFO c.s.a.w.service.OrderIntegrationTest - found the order!
16:23:05.299 [executor1-1] INFO c.s.api.web.service.OrderServiceImpl - updated order: 2884384
Other related code:
#Service
public class OrderServiceImpl implements OrderService {
#Autowired
private OrderDao orderDao;
#Async("executor1")
#Override
public void updateOrderAsync(Order order){
log.info("updating order: {}", order.getOrderId());
orderDao.updateOrder(order);
log.info("updated order: {}", order.getOrderId());
}
}
The DAO:
public interface OrderDao {
public int updateOrder(Order order);
public int createOrder(Order order);
public Order findOrderById(String orderId);
}
The Gradle dependencies:
dependencies {
compile 'org.springframework.boot:spring-boot-starter-jdbc'
compile 'org.springframework.boot:spring-boot-starter-security'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.mybatis.spring.boot:mybatis-spring-boot-starter:1.1.1'
compile 'ch.qos.logback:logback-classic:1.1.2'
compile 'org.springframework.boot:spring-boot-configuration-processor'
runtime 'mysql:mysql-connector-java'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile "org.springframework.security:spring-security-test"
}
The Spring configuration:
#SpringBootApplication
#EnableAsync
#EnableCaching
#EnableScheduling
#MapperScan("com.sapi.web.dao")
public class SapiApplication {
#Bean(name = "executor1")
protected Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(100);
return executor;
}
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource.primary")
public DataSource numberMasterDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "secondary")
#ConfigurationProperties(prefix = "datasource.secondary")
public DataSource provisioningDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "jdbcTpl")
public JdbcTemplate jdbcTemplate(#Qualifier("secondary") DataSource dsItems) {
return new JdbcTemplate(dsItems);
}
public static void main(String[] args) {
SpringApplication.run(SapiApplication.class, args);
}
}
The properties:
mybatis.mapper-locations=classpath*:com/sapi/web/dao/*Mapper.xml
mybatis.type-aliases-package=com.sapi.web.vo
datasource.primary.driver-class-name=com.mysql.jdbc.Driver
datasource.primary.url=jdbc:mysql://10.0.6.202:3306/sapi
datasource.primary.username=xxx
datasource.primary.password=xxx
datasource.primary.maximum-pool-size=80
datasource.primary.max-idle=10
datasource.primary.max-active=150
datasource.primary.max-wait=10000
datasource.primary.min-idle=5
datasource.primary.initial-size=5
datasource.primary.validation-query=SELECT 1
datasource.primary.test-on-borrow=false
datasource.primary.test-while-idle=true
datasource.primary.time-between-eviction-runs-millis=18800
datasource.primary.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=100)
datasource.secondary.url = jdbc:mysql://10.0.6.202:3306/xdb
datasource.secondary.username = xxx
datasource.secondary.password = xxx
datasource.secondary.driver-class-name = com.mysql.jdbc.Driver
logging.level.org.springframework.web=DEBUG
The problem you see is caused by the fact that the whole test method shouldUpdateOrder is executed in one transaction. This means that any update operation that is executed in the thread that runs shouldUpdateOrder locks the record for the whole duration of the transaction (that is till exit from test method) and that record cannot be updated by another concurrent transaction (that is executed in async method).
To solve the issue you need to change transactions boundaries. In your case the correct way to emulate real life usage is to
create order in one transaction and finish the transaction
update order in another transaction
check that update is executed as expected in yet another transaction

Resources