@Test public void handleF08RejectionWithPrepareLessThanMax() { InterledgerRejectPacket rejectPacket = interledgerRejectPacket(Optional.of( AmountTooLargeErrorData.builder() .receivedAmount(UnsignedLong.valueOf(2L)) .maximumAmount(UnsignedLong.valueOf(2L)) .build() )); assertThat(controller.handleF08Rejection(UnsignedLong.ONE, rejectPacket)).isEqualTo(UnsignedLong.ONE); }
@VisibleForTesting protected UnsignedLong handleF08Rejection( final UnsignedLong prepareAmount, final InterledgerRejectPacket rejectPacket ) { Objects.requireNonNull(prepareAmount, "prepareAmount must not be null"); Objects.requireNonNull(rejectPacket, "rejectPacket must not be null"); UnsignedLong newMaxPacketAmount; if (rejectPacket.getData().length > 0) { try { final AmountTooLargeErrorData amountTooLargeErrorData = streamCodecContext.read(AmountTooLargeErrorData.class, new ByteArrayInputStream(rejectPacket.getData())); final BigDecimal prepareAmountAsBigDecimal = new BigDecimal(prepareAmount.bigIntegerValue()); final BigDecimal detailsMaxAmount = new BigDecimal(amountTooLargeErrorData.maximumAmount().bigIntegerValue()); final BigDecimal detailsAmountReceived = new BigDecimal( amountTooLargeErrorData.receivedAmount().bigIntegerValue()); if (detailsAmountReceived.equals(BigDecimal.ZERO)) { newMaxPacketAmount = halvePrepareAmount(prepareAmount); } else { final BigDecimal newMaxPacketAmountAsBigDecimal = prepareAmountAsBigDecimal.multiply(detailsMaxAmount).divide(detailsAmountReceived, RoundingMode.FLOOR); newMaxPacketAmount = UnsignedLong.valueOf(newMaxPacketAmountAsBigDecimal.toBigIntegerExact()); } } catch (Exception e) { logger.warn("Unable to decode AmountTooLargeErrorData from F08 Reject packet. Setting newMaxPacketAmount to be " + "half the prepare amount. rejectPacket={} error={}", rejectPacket, e ); newMaxPacketAmount = halvePrepareAmount(prepareAmount); } } else { newMaxPacketAmount = halvePrepareAmount(prepareAmount); logger.warn( "F08 Reject packet had no data payload. Setting newMaxPacketAmount to be {} (half the prepare amount)", newMaxPacketAmount ); } final UnsignedLong newMaxPacketAmountFinal = newMaxPacketAmount; return this.maxPacketAmount .map($ -> StreamUtils.min($, newMaxPacketAmountFinal)) .orElse(newMaxPacketAmount); }
AimdCongestionController implements CongestionController { @VisibleForTesting protected UnsignedLong handleF08Rejection( final UnsignedLong prepareAmount, final InterledgerRejectPacket rejectPacket ) { Objects.requireNonNull(prepareAmount, "prepareAmount must not be null"); Objects.requireNonNull(rejectPacket, "rejectPacket must not be null"); UnsignedLong newMaxPacketAmount; if (rejectPacket.getData().length > 0) { try { final AmountTooLargeErrorData amountTooLargeErrorData = streamCodecContext.read(AmountTooLargeErrorData.class, new ByteArrayInputStream(rejectPacket.getData())); final BigDecimal prepareAmountAsBigDecimal = new BigDecimal(prepareAmount.bigIntegerValue()); final BigDecimal detailsMaxAmount = new BigDecimal(amountTooLargeErrorData.maximumAmount().bigIntegerValue()); final BigDecimal detailsAmountReceived = new BigDecimal( amountTooLargeErrorData.receivedAmount().bigIntegerValue()); if (detailsAmountReceived.equals(BigDecimal.ZERO)) { newMaxPacketAmount = halvePrepareAmount(prepareAmount); } else { final BigDecimal newMaxPacketAmountAsBigDecimal = prepareAmountAsBigDecimal.multiply(detailsMaxAmount).divide(detailsAmountReceived, RoundingMode.FLOOR); newMaxPacketAmount = UnsignedLong.valueOf(newMaxPacketAmountAsBigDecimal.toBigIntegerExact()); } } catch (Exception e) { logger.warn("Unable to decode AmountTooLargeErrorData from F08 Reject packet. Setting newMaxPacketAmount to be " + "half the prepare amount. rejectPacket={} error={}", rejectPacket, e ); newMaxPacketAmount = halvePrepareAmount(prepareAmount); } } else { newMaxPacketAmount = halvePrepareAmount(prepareAmount); logger.warn( "F08 Reject packet had no data payload. Setting newMaxPacketAmount to be {} (half the prepare amount)", newMaxPacketAmount ); } final UnsignedLong newMaxPacketAmountFinal = newMaxPacketAmount; return this.maxPacketAmount .map($ -> StreamUtils.min($, newMaxPacketAmountFinal)) .orElse(newMaxPacketAmount); } }
AimdCongestionController implements CongestionController { @VisibleForTesting protected UnsignedLong handleF08Rejection( final UnsignedLong prepareAmount, final InterledgerRejectPacket rejectPacket ) { Objects.requireNonNull(prepareAmount, "prepareAmount must not be null"); Objects.requireNonNull(rejectPacket, "rejectPacket must not be null"); UnsignedLong newMaxPacketAmount; if (rejectPacket.getData().length > 0) { try { final AmountTooLargeErrorData amountTooLargeErrorData = streamCodecContext.read(AmountTooLargeErrorData.class, new ByteArrayInputStream(rejectPacket.getData())); final BigDecimal prepareAmountAsBigDecimal = new BigDecimal(prepareAmount.bigIntegerValue()); final BigDecimal detailsMaxAmount = new BigDecimal(amountTooLargeErrorData.maximumAmount().bigIntegerValue()); final BigDecimal detailsAmountReceived = new BigDecimal( amountTooLargeErrorData.receivedAmount().bigIntegerValue()); if (detailsAmountReceived.equals(BigDecimal.ZERO)) { newMaxPacketAmount = halvePrepareAmount(prepareAmount); } else { final BigDecimal newMaxPacketAmountAsBigDecimal = prepareAmountAsBigDecimal.multiply(detailsMaxAmount).divide(detailsAmountReceived, RoundingMode.FLOOR); newMaxPacketAmount = UnsignedLong.valueOf(newMaxPacketAmountAsBigDecimal.toBigIntegerExact()); } } catch (Exception e) { logger.warn("Unable to decode AmountTooLargeErrorData from F08 Reject packet. Setting newMaxPacketAmount to be " + "half the prepare amount. rejectPacket={} error={}", rejectPacket, e ); newMaxPacketAmount = halvePrepareAmount(prepareAmount); } } else { newMaxPacketAmount = halvePrepareAmount(prepareAmount); logger.warn( "F08 Reject packet had no data payload. Setting newMaxPacketAmount to be {} (half the prepare amount)", newMaxPacketAmount ); } final UnsignedLong newMaxPacketAmountFinal = newMaxPacketAmount; return this.maxPacketAmount .map($ -> StreamUtils.min($, newMaxPacketAmountFinal)) .orElse(newMaxPacketAmount); } AimdCongestionController();  AimdCongestionController(
      final UnsignedLong startAmount, final UnsignedLong increaseAmount, final BigDecimal decreaseFactor,
      final CodecContext streamCodecContext
  ); }
AimdCongestionController implements CongestionController { @VisibleForTesting protected UnsignedLong handleF08Rejection( final UnsignedLong prepareAmount, final InterledgerRejectPacket rejectPacket ) { Objects.requireNonNull(prepareAmount, "prepareAmount must not be null"); Objects.requireNonNull(rejectPacket, "rejectPacket must not be null"); UnsignedLong newMaxPacketAmount; if (rejectPacket.getData().length > 0) { try { final AmountTooLargeErrorData amountTooLargeErrorData = streamCodecContext.read(AmountTooLargeErrorData.class, new ByteArrayInputStream(rejectPacket.getData())); final BigDecimal prepareAmountAsBigDecimal = new BigDecimal(prepareAmount.bigIntegerValue()); final BigDecimal detailsMaxAmount = new BigDecimal(amountTooLargeErrorData.maximumAmount().bigIntegerValue()); final BigDecimal detailsAmountReceived = new BigDecimal( amountTooLargeErrorData.receivedAmount().bigIntegerValue()); if (detailsAmountReceived.equals(BigDecimal.ZERO)) { newMaxPacketAmount = halvePrepareAmount(prepareAmount); } else { final BigDecimal newMaxPacketAmountAsBigDecimal = prepareAmountAsBigDecimal.multiply(detailsMaxAmount).divide(detailsAmountReceived, RoundingMode.FLOOR); newMaxPacketAmount = UnsignedLong.valueOf(newMaxPacketAmountAsBigDecimal.toBigIntegerExact()); } } catch (Exception e) { logger.warn("Unable to decode AmountTooLargeErrorData from F08 Reject packet. Setting newMaxPacketAmount to be " + "half the prepare amount. rejectPacket={} error={}", rejectPacket, e ); newMaxPacketAmount = halvePrepareAmount(prepareAmount); } } else { newMaxPacketAmount = halvePrepareAmount(prepareAmount); logger.warn( "F08 Reject packet had no data payload. Setting newMaxPacketAmount to be {} (half the prepare amount)", newMaxPacketAmount ); } final UnsignedLong newMaxPacketAmountFinal = newMaxPacketAmount; return this.maxPacketAmount .map($ -> StreamUtils.min($, newMaxPacketAmountFinal)) .orElse(newMaxPacketAmount); } AimdCongestionController();  AimdCongestionController(
      final UnsignedLong startAmount, final UnsignedLong increaseAmount, final BigDecimal decreaseFactor,
      final CodecContext streamCodecContext
  ); @Override UnsignedLong getMaxAmount(); @Override void prepare(final UnsignedLong amount); @Override void fulfill(final UnsignedLong prepareAmount); @Override void reject(final UnsignedLong prepareAmount, final InterledgerRejectPacket rejectPacket); @Override CongestionState getCongestionState(); void setCongestionState(final CongestionState congestionState); @Override Optional<UnsignedLong> getMaxPacketAmount(); void setMaxPacketAmount(final UnsignedLong maxPacketAmount); void setMaxPacketAmount(final Optional<UnsignedLong> maxPacketAmount); @Override boolean hasInFlight(); }
AimdCongestionController implements CongestionController { @VisibleForTesting protected UnsignedLong handleF08Rejection( final UnsignedLong prepareAmount, final InterledgerRejectPacket rejectPacket ) { Objects.requireNonNull(prepareAmount, "prepareAmount must not be null"); Objects.requireNonNull(rejectPacket, "rejectPacket must not be null"); UnsignedLong newMaxPacketAmount; if (rejectPacket.getData().length > 0) { try { final AmountTooLargeErrorData amountTooLargeErrorData = streamCodecContext.read(AmountTooLargeErrorData.class, new ByteArrayInputStream(rejectPacket.getData())); final BigDecimal prepareAmountAsBigDecimal = new BigDecimal(prepareAmount.bigIntegerValue()); final BigDecimal detailsMaxAmount = new BigDecimal(amountTooLargeErrorData.maximumAmount().bigIntegerValue()); final BigDecimal detailsAmountReceived = new BigDecimal( amountTooLargeErrorData.receivedAmount().bigIntegerValue()); if (detailsAmountReceived.equals(BigDecimal.ZERO)) { newMaxPacketAmount = halvePrepareAmount(prepareAmount); } else { final BigDecimal newMaxPacketAmountAsBigDecimal = prepareAmountAsBigDecimal.multiply(detailsMaxAmount).divide(detailsAmountReceived, RoundingMode.FLOOR); newMaxPacketAmount = UnsignedLong.valueOf(newMaxPacketAmountAsBigDecimal.toBigIntegerExact()); } } catch (Exception e) { logger.warn("Unable to decode AmountTooLargeErrorData from F08 Reject packet. Setting newMaxPacketAmount to be " + "half the prepare amount. rejectPacket={} error={}", rejectPacket, e ); newMaxPacketAmount = halvePrepareAmount(prepareAmount); } } else { newMaxPacketAmount = halvePrepareAmount(prepareAmount); logger.warn( "F08 Reject packet had no data payload. Setting newMaxPacketAmount to be {} (half the prepare amount)", newMaxPacketAmount ); } final UnsignedLong newMaxPacketAmountFinal = newMaxPacketAmount; return this.maxPacketAmount .map($ -> StreamUtils.min($, newMaxPacketAmountFinal)) .orElse(newMaxPacketAmount); } AimdCongestionController();  AimdCongestionController(
      final UnsignedLong startAmount, final UnsignedLong increaseAmount, final BigDecimal decreaseFactor,
      final CodecContext streamCodecContext
  ); @Override UnsignedLong getMaxAmount(); @Override void prepare(final UnsignedLong amount); @Override void fulfill(final UnsignedLong prepareAmount); @Override void reject(final UnsignedLong prepareAmount, final InterledgerRejectPacket rejectPacket); @Override CongestionState getCongestionState(); void setCongestionState(final CongestionState congestionState); @Override Optional<UnsignedLong> getMaxPacketAmount(); void setMaxPacketAmount(final UnsignedLong maxPacketAmount); void setMaxPacketAmount(final Optional<UnsignedLong> maxPacketAmount); @Override boolean hasInFlight();  }