RES: [corda-dev] #Corda Unable to process a transaction containing big amount of states due to exceeded message size limit #Corda
GEORGE MARCEL MONTEIRO ARCURI SMETANA
Hi, Oleksandra,
Hope you are doing fine? If you are the owner of the network, maybe you can raise the maxMessageSize and the maxTransactionSize network parameters:
https://docs.corda.net/docs/cenm/1.3/config-network-parameters.html
Anyway, are all these states and obligations from the same Parties in this big transaction? If they are not, you might be leaking some confidential information, since in order to validate the transaction, the receiving partner will have to check de dependency chain of thousands of states.
Best regards,
BANCO BRADESCO S.A. 4251 / Departamento de Pesquisa e Inovação Pesquisas Especiais George Marcel M. A. Smetana Tel.: 11 3684-8460, ramal: (2)48460 – Fax: 11 3684-8351 mailto: george.smetana@...
Attachments are limited to 2MB
De: corda-dev@groups.io <corda-dev@groups.io>
Em nome de oleksandra@...
Hi guys, Message exceeds maxMessageSize network parameter, maxMessageSize: [10485760] when the number of the states in one transaction is big. I understand that this is a logical/robust check on the ArtemisMQ side since as more bytes 1 message contains - more chances to fail during the network transmission.
I'll try to describe the details with code examples of the issue: Use case: we have the states which represents obligations (Obligation State), and the state that represents a payment. One payment state can cover multiple obligations and settle them. So the structure of the Payment is:
data class PaymentState( val paymentItems: List<PaymentItem>, override val linearId: UniqueIdentifier = UniqueIdentifier() ) : LinearState, QueryableState { ... }
data class PaymentItem( val id: UUID = UUID.randomUUID(), val obligationId: UUID, val amount: Amount ) // not a state just a child
data class ObligationState( val amount: Amount, // initial obligation amount val availableAmount, // initially = remaining/settled/paid amount, and will be reduced when be payed/settled override val linearId: UniqueIdentifier = UniqueIdentifier() ) : LinearState, QueryableState { ... }
The user1 creates 1000 obligations during the month (not a single operation) One corda transaction can be described like this: - Input State and Refs - 1000 obligation state&refs (prev versions) - Output States - 1000 obligation states with updated money (states that have to be updated), 1 Payment State (state that has to be created)
So the described example contains a lot of states in the same transaction which leads us to have a huge message to be sent to another party. And potentially have a situation when the message will exceed its limit (for example if the Payment was raised to cover more states ~1300 will exceed the limit).
So we've tried to think about diving this transaction into multiple small parts. But faced that if we do it separately it will lead to the situation when one of them possibly can fail, since the others were Finalized they can't be rollbacked, since it's no more than 1 transaction that can be rollbacked if smth happened.
Please find the code in the attachment PaymentCreateDemo.kts (not actual, simplified one, in order to reflect the work with states, flows, subflows). The first attempt of resolving msg limits error.
The dividing into pieces we've done in two approaches, firstly we've tried to update the ObligationStates chunked them by 500 in one tx (each tx processing in the subflow separately), and when all txs completed it's ready to create a PaymentState in another tx. This has two drawbacks, 1st it's no more than 1 transaction and the rollback of prev txs is impossible, the 2nd - PaymentState can have any number of PaymentItems and if it's approximately 86.000 it will exceed the limit of message size too.
The second approach was to have an additional state to aggregate the PaymentItems in groups. Each group has a max size=500 of items. So if it's 1000 items it will be divided into 2 groups for 1 payment. This resolved the issue of the second drawback described in a prev paragraph.
data class PaymentState( override val linearId: UniqueIdentifier = UniqueIdentifier(), val version: Int // no more contains items ) : LinearState, QueryableState { ... }
data class PaymentItemGroup( val paymentStateId: UUID, // check always the head state val paymentItems: List<PaymentItem>, override val linearId: UniqueIdentifier = UniqueIdentifier() ) : LinearState, QueryableState { ... }
I've attached schemas describing the sequential processing of the subflows and parallel one - to speed up the sharing process. But still, we have a situation when one of the transactions will fail and only part of the actual payment was reflected as paid/settled on obligations.
Thanks
|
|
|
|
oleksandra@...
On Fri, Oct 23, 2020 at 12:02 AM, GEORGE MARCEL MONTEIRO ARCURI SMETANA wrote:
are all these states and obligations from the same Parties in this big transaction? Hi George, thank you for your answer, yes all the states correspond to the same parties. That's just such a requirement of the use case, cover transactionally in one payment many obligations.
The default values are:
const val DEFAULT_MAX_MESSAGE_SIZE: Int = 10485760 // ~10mb
const val DEFAULT_MAX_TRANSACTION_SIZE: Int = 524288000 // ~50mb
I guess that's not recommended to increase these values, plus later it won't be a private network, but cordite. That's why in this topic I'm trying to find help to understand is it possible in Corda to divide data but still do it transactionally. Thanks, Alex
|
|
|