Search in sources :

Example 1 with StagingTransaction

use of com.quorum.tessera.data.staging.StagingTransaction in project tessera by ConsenSys.

the class StagingEntityDAOTest method createFixtures.

public Map<String, StagingTransaction> createFixtures() {
    final EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();
    final String txnHash1 = Utils.createHashStr();
    final StagingTransaction stTransaction1 = new StagingTransaction();
    stTransaction1.setId(1L);
    stTransaction1.setHash(txnHash1);
    stTransaction1.setEncodedPayloadCodec(CODEC);
    entityManager.persist(stTransaction1);
    final String txnHash2 = Utils.createHashStr();
    final StagingTransaction stTransaction2a = new StagingTransaction();
    stTransaction2a.setId(21L);
    stTransaction2a.setHash(txnHash2);
    stTransaction2a.setEncodedPayloadCodec(CODEC);
    StagingAffectedTransaction stAffectedContractTransaction21a = new StagingAffectedTransaction();
    stAffectedContractTransaction21a.setHash(txnHash1);
    stAffectedContractTransaction21a.setSourceTransaction(stTransaction2a);
    stTransaction2a.getAffectedContractTransactions().add(stAffectedContractTransaction21a);
    entityManager.persist(stTransaction2a);
    // Another version of transaction 2
    final StagingTransaction stTransaction2b = new StagingTransaction();
    stTransaction2b.setId(22L);
    stTransaction2b.setHash(txnHash2);
    stTransaction2b.setEncodedPayloadCodec(CODEC);
    StagingAffectedTransaction stAffectedContractTransaction21b = new StagingAffectedTransaction();
    stAffectedContractTransaction21b.setHash(txnHash1);
    stAffectedContractTransaction21b.setSourceTransaction(stTransaction2b);
    stTransaction2b.getAffectedContractTransactions().add(stAffectedContractTransaction21b);
    entityManager.persist(stTransaction2b);
    final String txnHash4 = Utils.createHashStr();
    // we are storing a transaction TXN4 which depends on another transaction TXN3 (which has not
    // been received yet)
    final String txnHash3 = Utils.createHashStr();
    final StagingTransaction stTransaction4 = new StagingTransaction();
    stTransaction4.setId(4L);
    stTransaction4.setHash(txnHash4);
    stTransaction4.setEncodedPayloadCodec(CODEC);
    StagingAffectedTransaction stAffectedContractTransaction43 = new StagingAffectedTransaction();
    stAffectedContractTransaction43.setHash(txnHash3);
    stAffectedContractTransaction43.setSourceTransaction(stTransaction4);
    stTransaction4.getAffectedContractTransactions().add(stAffectedContractTransaction43);
    entityManager.persist(stTransaction4);
    final StagingTransaction stTransaction3 = new StagingTransaction();
    stTransaction3.setHash(txnHash3);
    stTransaction3.setId(3L);
    stTransaction3.setEncodedPayloadCodec(CODEC);
    StagingAffectedTransaction stAffectedContractTransaction31 = new StagingAffectedTransaction();
    stAffectedContractTransaction31.setHash(txnHash1);
    stAffectedContractTransaction31.setSourceTransaction(stTransaction3);
    stTransaction3.getAffectedContractTransactions().add(stAffectedContractTransaction31);
    entityManager.persist(stTransaction3);
    final String txnHash5 = Utils.createHashStr();
    // TXN5 is a unresolvable transaction as it depends on TXN6 which is never received
    final String txnHash6 = Utils.createHashStr();
    final StagingTransaction stTransaction5 = new StagingTransaction();
    stTransaction5.setHash(txnHash5);
    stTransaction5.setId(5L);
    stTransaction5.setEncodedPayloadCodec(CODEC);
    StagingAffectedTransaction stAffectedContractTransaction56 = new StagingAffectedTransaction();
    stAffectedContractTransaction56.setHash(txnHash6);
    stAffectedContractTransaction56.setSourceTransaction(stTransaction5);
    stTransaction5.getAffectedContractTransactions().add(stAffectedContractTransaction56);
    entityManager.persist(stTransaction5);
    final String txnHash7 = Utils.createHashStr();
    // TXN7 depends on TXN1 and TXN3
    final StagingTransaction stTransaction7 = new StagingTransaction();
    stTransaction7.setHash(txnHash7);
    stTransaction7.setId(7L);
    stTransaction7.setEncodedPayloadCodec(CODEC);
    StagingAffectedTransaction stAffectedContractTransaction71 = new StagingAffectedTransaction();
    stAffectedContractTransaction71.setHash(txnHash1);
    stAffectedContractTransaction71.setSourceTransaction(stTransaction7);
    stTransaction7.getAffectedContractTransactions().add(stAffectedContractTransaction71);
    StagingAffectedTransaction stAffectedContractTransaction74 = new StagingAffectedTransaction();
    stAffectedContractTransaction74.setHash(txnHash4);
    stAffectedContractTransaction74.setSourceTransaction(stTransaction7);
    stTransaction7.getAffectedContractTransactions().add(stAffectedContractTransaction74);
    entityManager.persist(stTransaction7);
    entityManager.getTransaction().commit();
    Map<String, StagingTransaction> transactions = new HashMap<>();
    transactions.put("TXN1", stTransaction1);
    transactions.put("TXN2A", stTransaction2a);
    transactions.put("TXN2B", stTransaction2b);
    transactions.put("TXN3", stTransaction3);
    transactions.put("TXN4", stTransaction4);
    transactions.put("TXN5", stTransaction5);
    transactions.put("TXN7", stTransaction7);
    return transactions;
}
Also used : StagingAffectedTransaction(com.quorum.tessera.data.staging.StagingAffectedTransaction) StagingTransaction(com.quorum.tessera.data.staging.StagingTransaction)

Example 2 with StagingTransaction

use of com.quorum.tessera.data.staging.StagingTransaction in project tessera by ConsenSys.

the class BatchResendManagerImplTest method testStoreResendBatchMultipleVersions.

@Test
public void testStoreResendBatchMultipleVersions() {
    try (var payloadDigestMockedStatic = mockStatic(PayloadDigest.class);
        var payloadEncoderMockedStatic = mockStatic(PayloadEncoder.class)) {
        payloadDigestMockedStatic.when(PayloadDigest::create).thenReturn((PayloadDigest) cipherText -> cipherText);
        payloadEncoderMockedStatic.when(() -> PayloadEncoder.create(any())).thenReturn(payloadEncoder);
        final EncodedPayload encodedPayload = EncodedPayload.Builder.create().withSenderKey(publicKey).withCipherText("cipherText".getBytes()).withCipherTextNonce(new Nonce("nonce".getBytes())).withRecipientBoxes(singletonList("box".getBytes())).withRecipientNonce(new Nonce("recipientNonce".getBytes())).withRecipientKeys(singletonList(PublicKey.from("receiverKey".getBytes()))).withPrivacyMode(PrivacyMode.STANDARD_PRIVATE).withAffectedContractTransactions(emptyMap()).withExecHash(new byte[0]).build();
        when(payloadEncoder.decode(any())).thenReturn(encodedPayload);
        final byte[] raw = new PayloadEncoderImpl().encode(encodedPayload);
        PushBatchRequest request = PushBatchRequest.from(List.of(raw), EncodedPayloadCodec.LEGACY);
        StagingTransaction existing = new StagingTransaction();
        when(stagingEntityDAO.retrieveByHash(any())).thenReturn(Optional.of(existing));
        when(stagingEntityDAO.update(any(StagingTransaction.class))).thenReturn(new StagingTransaction());
        manager.storeResendBatch(request);
        verify(stagingEntityDAO).save(any(StagingTransaction.class));
        verify(payloadEncoder).decode(any());
        verify(payloadEncoder).encodedPayloadCodec();
        payloadDigestMockedStatic.verify(PayloadDigest::create);
        payloadDigestMockedStatic.verifyNoMoreInteractions();
    }
}
Also used : AdditionalMatchers.lt(org.mockito.AdditionalMatchers.lt) ResendBatchRequest(com.quorum.tessera.recovery.resend.ResendBatchRequest) IntStream(java.util.stream.IntStream) PublicKey(com.quorum.tessera.encryption.PublicKey) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) BatchWorkflowFactory(com.quorum.tessera.recovery.workflow.BatchWorkflowFactory) BatchResendManager(com.quorum.tessera.recovery.workflow.BatchResendManager) Base64Codec(com.quorum.tessera.base64.Base64Codec) EncryptedTransaction(com.quorum.tessera.data.EncryptedTransaction) BatchWorkflow(com.quorum.tessera.recovery.workflow.BatchWorkflow) Collections.singletonList(java.util.Collections.singletonList) PushBatchRequest(com.quorum.tessera.recovery.resend.PushBatchRequest) BatchWorkflowContext(com.quorum.tessera.recovery.workflow.BatchWorkflowContext) StagingEntityDAO(com.quorum.tessera.data.staging.StagingEntityDAO) EncryptedTransactionDAO(com.quorum.tessera.data.EncryptedTransactionDAO) After(org.junit.After) Before(org.junit.Before) Collections.emptyMap(java.util.Collections.emptyMap) AdditionalMatchers.gt(org.mockito.AdditionalMatchers.gt) com.quorum.tessera.enclave(com.quorum.tessera.enclave) Nonce(com.quorum.tessera.encryption.Nonce) ServiceLoader(java.util.ServiceLoader) Test(org.junit.Test) StagingTransaction(com.quorum.tessera.data.staging.StagingTransaction) Collectors(java.util.stream.Collectors) Mockito(org.mockito.Mockito) List(java.util.List) ResendBatchResponse(com.quorum.tessera.recovery.resend.ResendBatchResponse) Optional(java.util.Optional) Nonce(com.quorum.tessera.encryption.Nonce) PushBatchRequest(com.quorum.tessera.recovery.resend.PushBatchRequest) StagingTransaction(com.quorum.tessera.data.staging.StagingTransaction) Test(org.junit.Test)

Example 3 with StagingTransaction

use of com.quorum.tessera.data.staging.StagingTransaction in project tessera by ConsenSys.

the class RecoveryImplTest method testSyncPsvTransactionOnlySentOnce.

@Test
public void testSyncPsvTransactionOnlySentOnce() {
    StagingTransaction version1 = mock(StagingTransaction.class);
    StagingTransaction version2 = mock(StagingTransaction.class);
    StagingTransaction anotherTx = mock(StagingTransaction.class);
    when(version1.getHash()).thenReturn("TXN1");
    when(version2.getHash()).thenReturn("TXN1");
    when(anotherTx.getHash()).thenReturn("TXN2");
    EncodedPayload encodedPayload = mock(EncodedPayload.class);
    EncodedPayload encodedPayload2 = mock(EncodedPayload.class);
    when(version1.getEncodedPayload()).thenReturn(encodedPayload);
    when(version2.getEncodedPayload()).thenReturn(encodedPayload);
    when(anotherTx.getEncodedPayload()).thenReturn(encodedPayload2);
    when(version1.getPrivacyMode()).thenReturn(PrivacyMode.PRIVATE_STATE_VALIDATION);
    when(version2.getPrivacyMode()).thenReturn(PrivacyMode.PRIVATE_STATE_VALIDATION);
    when(anotherTx.getPrivacyMode()).thenReturn(PrivacyMode.STANDARD_PRIVATE);
    when(stagingEntityDAO.retrieveTransactionBatchOrderByStageAndHash(anyInt(), anyInt())).thenReturn(List.of(version1, version2, anotherTx));
    when(stagingEntityDAO.countAll()).thenReturn(3L);
    when(transactionManager.storePayload(any())).thenThrow(PrivacyViolationException.class);
    RecoveryResult result = recovery.sync();
    assertThat(result).isEqualTo(RecoveryResult.FAILURE);
    verify(stagingEntityDAO).retrieveTransactionBatchOrderByStageAndHash(anyInt(), anyInt());
    verify(stagingEntityDAO, times(2)).countAll();
    verify(transactionManager).storePayload(encodedPayload);
    verify(transactionManager).storePayload(encodedPayload2);
}
Also used : StagingTransaction(com.quorum.tessera.data.staging.StagingTransaction) EncodedPayload(com.quorum.tessera.enclave.EncodedPayload) RecoveryResult(com.quorum.tessera.recovery.RecoveryResult) Test(org.junit.Test)

Example 4 with StagingTransaction

use of com.quorum.tessera.data.staging.StagingTransaction in project tessera by ConsenSys.

the class RecoveryImpl method sync.

@Override
public RecoveryResult sync() {
    final AtomicInteger payloadCount = new AtomicInteger(0);
    final AtomicInteger syncFailureCount = new AtomicInteger(0);
    final int maxResult = BATCH_SIZE;
    for (int offset = 0; offset < stagingEntityDAO.countAll(); offset += maxResult) {
        final List<StagingTransaction> transactions = stagingEntityDAO.retrieveTransactionBatchOrderByStageAndHash(offset, maxResult);
        final Map<String, List<StagingTransaction>> grouped = transactions.stream().collect(Collectors.groupingBy(StagingTransaction::getHash, LinkedHashMap::new, toList()));
        grouped.forEach((key, value) -> value.stream().filter(t -> {
            payloadCount.incrementAndGet();
            EncodedPayload encodedPayload = t.getEncodedPayload();
            try {
                transactionManager.storePayload(encodedPayload);
            } catch (PrivacyViolationException | PersistenceException ex) {
                LOGGER.error("An error occurred during batch resend sync stage.", ex);
                syncFailureCount.incrementAndGet();
            }
            return PrivacyMode.PRIVATE_STATE_VALIDATION == t.getPrivacyMode();
        }).findFirst());
    }
    if (syncFailureCount.get() > 0) {
        LOGGER.warn("There have been issues during the synchronisation process. " + "Problematic transactions have been ignored.");
        if (syncFailureCount.get() == payloadCount.get()) {
            return RecoveryResult.FAILURE;
        }
        return RecoveryResult.PARTIAL_SUCCESS;
    }
    return RecoveryResult.SUCCESS;
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) PrivacyViolationException(com.quorum.tessera.transaction.exception.PrivacyViolationException) PersistenceException(jakarta.persistence.PersistenceException) StagingTransaction(com.quorum.tessera.data.staging.StagingTransaction) Collectors.toList(java.util.stream.Collectors.toList) EncodedPayload(com.quorum.tessera.enclave.EncodedPayload)

Example 5 with StagingTransaction

use of com.quorum.tessera.data.staging.StagingTransaction in project tessera by ConsenSys.

the class RecoveryImplTest method testSyncPartialSuccess.

@Test
public void testSyncPartialSuccess() {
    StagingTransaction version1 = mock(StagingTransaction.class);
    StagingTransaction version2 = mock(StagingTransaction.class);
    when(version1.getHash()).thenReturn("TXN1");
    when(version2.getHash()).thenReturn("TXN1");
    when(stagingEntityDAO.retrieveTransactionBatchOrderByStageAndHash(anyInt(), anyInt())).thenReturn(List.of(version1, version2));
    when(stagingEntityDAO.countAll()).thenReturn(2L);
    EncodedPayload encodedPayload = mock(EncodedPayload.class);
    EncodedPayload encodedPayload2 = mock(EncodedPayload.class);
    when(version1.getEncodedPayload()).thenReturn(encodedPayload);
    when(version2.getEncodedPayload()).thenReturn(encodedPayload2);
    when(transactionManager.storePayload(encodedPayload)).thenThrow(PrivacyViolationException.class);
    RecoveryResult result = recovery.sync();
    assertThat(result).isEqualTo(RecoveryResult.PARTIAL_SUCCESS);
    verify(stagingEntityDAO).retrieveTransactionBatchOrderByStageAndHash(anyInt(), anyInt());
    verify(stagingEntityDAO, times(2)).countAll();
    verify(transactionManager).storePayload(encodedPayload);
    verify(transactionManager).storePayload(encodedPayload2);
}
Also used : StagingTransaction(com.quorum.tessera.data.staging.StagingTransaction) EncodedPayload(com.quorum.tessera.enclave.EncodedPayload) RecoveryResult(com.quorum.tessera.recovery.RecoveryResult) Test(org.junit.Test)

Aggregations

StagingTransaction (com.quorum.tessera.data.staging.StagingTransaction)13 Test (org.junit.Test)10 EncodedPayload (com.quorum.tessera.enclave.EncodedPayload)7 StagingAffectedTransaction (com.quorum.tessera.data.staging.StagingAffectedTransaction)4 RecoveryResult (com.quorum.tessera.recovery.RecoveryResult)4 CriteriaBuilder (jakarta.persistence.criteria.CriteriaBuilder)4 StagingEntityDAO (com.quorum.tessera.data.staging.StagingEntityDAO)3 AtomicLong (java.util.concurrent.atomic.AtomicLong)3 Collectors (java.util.stream.Collectors)3 Assertions.assertThat (org.assertj.core.api.Assertions.assertThat)3 After (org.junit.After)3 Before (org.junit.Before)3 Mockito (org.mockito.Mockito)3 TestConfig (com.quorum.tessera.data.TestConfig)2 Utils (com.quorum.tessera.data.Utils)2 EncodedPayloadCodec (com.quorum.tessera.enclave.EncodedPayloadCodec)2 PayloadEncoder (com.quorum.tessera.enclave.PayloadEncoder)2 PrivacyMode (com.quorum.tessera.enclave.PrivacyMode)2 jakarta.persistence (jakarta.persistence)2 CriteriaQuery (jakarta.persistence.criteria.CriteriaQuery)2