class PrivateTransaction {

  @SuppressWarnings({"unchecked"})
  public static PrivateTransaction readFrom(final RLPInput input) throws RLPException {
    input.enterList();

    final Builder builder =
        builder()
            .nonce(input.readLongScalar())
            .gasPrice(Wei.of(input.readUInt256Scalar()))
            .gasLimit(input.readLongScalar())
            .to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v)))
            .value(Wei.of(input.readUInt256Scalar()))
            .payload(input.readBytes());

    final BigInteger v = input.readBigIntegerScalar();
    final byte recId;
    Optional<BigInteger> chainId = Optional.empty();
    if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) {
      recId = v.subtract(REPLAY_UNPROTECTED_V_BASE).byteValueExact();
    } else if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) {
      chainId = Optional.of(v.subtract(REPLAY_PROTECTED_V_BASE).divide(TWO));
      recId = v.subtract(TWO.multiply(chainId.get()).add(REPLAY_PROTECTED_V_BASE)).byteValueExact();
    } else {
      throw new RuntimeException(
          String.format("An unsupported encoded `v` value of %s was found", v));
    }
    final BigInteger r = input.readUInt256Scalar().toBytes().toUnsignedBigInteger();
    final BigInteger s = input.readUInt256Scalar().toBytes().toUnsignedBigInteger();
    final SECP256K1.Signature signature = SECP256K1.Signature.create(r, s, recId);

    final Bytes privateFrom = input.readBytes();
    final Object privateForOrPrivacyGroupId = resolvePrivateForOrPrivacyGroupId(input.readAsRlp());
    final Restriction restriction = convertToEnum(input.readBytes());

    input.leaveList();

    chainId.ifPresent(builder::chainId);

    if (privateForOrPrivacyGroupId instanceof List) {
      return builder
          .signature(signature)
          .privateFrom(privateFrom)
          .privateFor((List<Bytes>) privateForOrPrivacyGroupId)
          .restriction(restriction)
          .build();
    } else {
      return builder
          .signature(signature)
          .privateFrom(privateFrom)
          .privacyGroupId((Bytes) privateForOrPrivacyGroupId)
          .restriction(restriction)
          .build();
    }
  }

  protected  PrivateTransaction(
      final long nonce,
      final Wei gasPrice,
      final long gasLimit,
      final Optional<Address> to,
      final Wei value,
      final SECP256K1.Signature signature,
      final Bytes payload,
      final Address sender,
      final Optional<BigInteger> chainId,
      final Bytes privateFrom,
      final Optional<List<Bytes>> privateFor,
      final Optional<Bytes> privacyGroupId,
      final Restriction restriction);
  protected  PrivateTransaction(final PrivateTransaction privateTransaction);

}