@Test public void shouldAllowTransactionWhenAccountWhitelistControllerIsNotPresent() { givenTransactionIsValid(transaction1); assertThat(transactionPool.addLocalTransaction(transaction1)).isEqualTo(valid()); assertTransactionPending(transaction1); }
@Test public void shouldNotAddRemoteTransactionsThatAreInvalidAccordingToInvariantChecks() { givenTransactionIsValid(transaction2); when(transactionValidator.validate(transaction1)) .thenReturn(ValidationResult.invalid(NONCE_TOO_LOW)); transactionPool.addRemoteTransactions(asList(transaction1, transaction2)); assertTransactionNotPending(transaction1); assertTransactionPending(transaction2); verify(batchAddedListener).onTransactionsAdded(singleton(transaction2)); }
@Test public void shouldAllowWhitelistedTransactionWhenWhitelistEnabled() { transactionPool.setAccountWhitelist(accountWhitelistController); givenTransactionIsValid(transaction1); when(accountWhitelistController.isAccountWhiteListSet()).thenReturn(true); when(accountWhitelistController.contains(transaction1.getSender().toString())).thenReturn(true); assertThat(transactionPool.addLocalTransaction(transaction1)).isEqualTo(valid()); assertTransactionPending(transaction1); }
@Test public void shouldNotAddRemoteTransactionsThatAreInvalidAccordingToStateDependentChecks() { givenTransactionIsValid(transaction2); when(transactionValidator.validate(transaction1)).thenReturn(valid()); when(transactionValidator.validateForSender(transaction1, null, OptionalLong.empty())) .thenReturn(ValidationResult.invalid(NONCE_TOO_LOW)); transactionPool.addRemoteTransactions(asList(transaction1, transaction2)); assertTransactionNotPending(transaction1); assertTransactionPending(transaction2); verify(batchAddedListener).onTransactionsAdded(singleton(transaction2)); }
@Test public void shouldAllowSequenceOfTransactionsWithIncreasingNonceFromSameSenderWhenSentInBatchOutOfOrder() { final TransactionTestFixture builder = new TransactionTestFixture(); final Transaction transaction1 = builder.nonce(1).createTransaction(KEY_PAIR1); final Transaction transaction2 = builder.nonce(2).createTransaction(KEY_PAIR1); final Transaction transaction3 = builder.nonce(3).createTransaction(KEY_PAIR1); when(transactionValidator.validate(any(Transaction.class))).thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction1), nullable(Account.class), eq(OptionalLong.empty()))) .thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction2), nullable(Account.class), eq(OptionalLong.of(2)))) .thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction3), nullable(Account.class), eq(OptionalLong.of(3)))) .thenReturn(valid()); transactionPool.addRemoteTransactions(asList(transaction3, transaction1, transaction2)); assertTransactionPending(transaction1); assertTransactionPending(transaction2); assertTransactionPending(transaction3); }
@Test public void shouldAllowSequenceOfTransactionsWithIncreasingNonceFromSameSender() { final TransactionTestFixture builder = new TransactionTestFixture(); final Transaction transaction1 = builder.nonce(1).createTransaction(KEY_PAIR1); final Transaction transaction2 = builder.nonce(2).createTransaction(KEY_PAIR1); final Transaction transaction3 = builder.nonce(3).createTransaction(KEY_PAIR1); when(transactionValidator.validate(any(Transaction.class))).thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction1), nullable(Account.class), eq(OptionalLong.empty()))) .thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction2), nullable(Account.class), eq(OptionalLong.of(2)))) .thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction3), nullable(Account.class), eq(OptionalLong.of(3)))) .thenReturn(valid()); assertThat(transactionPool.addLocalTransaction(transaction1)).isEqualTo(valid()); assertThat(transactionPool.addLocalTransaction(transaction2)).isEqualTo(valid()); assertThat(transactionPool.addLocalTransaction(transaction3)).isEqualTo(valid()); assertTransactionPending(transaction1); assertTransactionPending(transaction2); assertTransactionPending(transaction3); }
@Test public void shouldRemoveTransactionsFromPendingListWhenIncludedInBlockOnChain() { transactions.addRemoteTransaction(transaction1); assertTransactionPending(transaction1); appendBlock(transaction1); assertTransactionNotPending(transaction1); }
@Test public void shouldNotNotifyBatchListenerWhenRemoteTransactionDoesNotReplaceExisting() { final TransactionTestFixture builder = new TransactionTestFixture(); final Transaction transaction1 = builder.nonce(1).gasPrice(Wei.of(10)).createTransaction(KEY_PAIR1); final Transaction transaction2 = builder.nonce(1).gasPrice(Wei.of(5)).createTransaction(KEY_PAIR1); when(transactionValidator.validate(any(Transaction.class))).thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction1), nullable(Account.class), eq(OptionalLong.empty()))) .thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction2), nullable(Account.class), eq(OptionalLong.of(2)))) .thenReturn(valid()); transactionPool.addRemoteTransactions(singletonList(transaction1)); transactionPool.addRemoteTransactions(singletonList(transaction2)); assertTransactionPending(transaction1); verify(batchAddedListener).onTransactionsAdded(singleton(transaction1)); verify(batchAddedListener, never()).onTransactionsAdded(singleton(transaction2)); }
@Test public void shouldNotNotifyBatchListenerWhenLocalTransactionDoesNotReplaceExisting() { final TransactionTestFixture builder = new TransactionTestFixture(); final Transaction transaction1 = builder.nonce(1).gasPrice(Wei.of(10)).createTransaction(KEY_PAIR1); final Transaction transaction2 = builder.nonce(1).gasPrice(Wei.of(5)).createTransaction(KEY_PAIR1); when(transactionValidator.validate(any(Transaction.class))).thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction1), nullable(Account.class), eq(OptionalLong.empty()))) .thenReturn(valid()); when(transactionValidator.validateForSender( eq(transaction2), nullable(Account.class), eq(OptionalLong.of(2)))) .thenReturn(valid()); transactionPool.addLocalTransaction(transaction1); transactionPool.addLocalTransaction(transaction2); assertTransactionPending(transaction1); verify(batchAddedListener).onTransactionsAdded(singletonList(transaction1)); verify(batchAddedListener, never()).onTransactionsAdded(singletonList(transaction2)); }
@Test public void shouldNotRemovePendingTransactionsWhenABlockAddedToAFork() { transactions.addRemoteTransaction(transaction1); final BlockHeader commonParent = getHeaderForCurrentChainHead(); final Block canonicalHead = appendBlock(UInt256.of(1000), commonParent); appendBlock(UInt256.ONE, commonParent, transaction1); verifyChainHeadIs(canonicalHead); assertTransactionPending(transaction1); }
@Test public void shouldReaddTransactionsFromThePreviousCanonicalHeadWhenAReorgOccurs() { givenTransactionIsValid(transaction1); givenTransactionIsValid(transaction2); transactions.addRemoteTransaction(transaction1); transactions.addRemoteTransaction(transaction2); final BlockHeader commonParent = getHeaderForCurrentChainHead(); final Block originalFork1 = appendBlock(UInt256.of(1000), commonParent, transaction1); final Block originalFork2 = appendBlock(UInt256.ONE, originalFork1.getHeader(), transaction2); assertTransactionNotPending(transaction1); assertTransactionNotPending(transaction2); final Block reorgFork1 = appendBlock(UInt256.ONE, commonParent); verifyChainHeadIs(originalFork2); transactions.addTransactionListener(listener); final Block reorgFork2 = appendBlock(UInt256.of(2000), reorgFork1.getHeader()); verifyChainHeadIs(reorgFork2); assertTransactionPending(transaction1); assertTransactionPending(transaction2); verify(listener).onTransactionAdded(transaction1); verify(listener).onTransactionAdded(transaction2); verifyNoMoreInteractions(listener); }
@Test public void shouldNotReaddTransactionsThatAreInBothForksWhenReorgHappens() { givenTransactionIsValid(transaction1); givenTransactionIsValid(transaction2); transactions.addRemoteTransaction(transaction1); transactions.addRemoteTransaction(transaction2); final BlockHeader commonParent = getHeaderForCurrentChainHead(); final Block originalFork1 = appendBlock(UInt256.of(1000), commonParent, transaction1); final Block originalFork2 = appendBlock(UInt256.ONE, originalFork1.getHeader(), transaction2); assertTransactionNotPending(transaction1); assertTransactionNotPending(transaction2); final Block reorgFork1 = appendBlock(UInt256.ONE, commonParent, transaction1); verifyChainHeadIs(originalFork2); final Block reorgFork2 = appendBlock(UInt256.of(2000), reorgFork1.getHeader()); verifyChainHeadIs(reorgFork2); assertTransactionNotPending(transaction1); assertTransactionPending(transaction2); }