Skip to content

Commit

Permalink
add support for different chains
Browse files Browse the repository at this point in the history
  • Loading branch information
C-Otto committed Feb 22, 2022
1 parent 7cfb9e3 commit 4892721
Show file tree
Hide file tree
Showing 162 changed files with 2,166 additions and 952 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import de.cotto.bitbook.backend.model.AddressTransactions;
import de.cotto.bitbook.backend.model.Provider;
import de.cotto.bitbook.backend.model.ProviderException;

import java.util.Optional;

import static de.cotto.bitbook.backend.model.Chain.BTC;

public abstract class SimpleAddressTransactionsProvider
implements Provider<TransactionsRequestKey, AddressTransactions> {

Expand All @@ -13,13 +16,19 @@ public SimpleAddressTransactionsProvider() {
}

@Override
public Optional<AddressTransactions> get(TransactionsRequestKey transactionsRequestKey) {
public Optional<AddressTransactions> get(TransactionsRequestKey transactionsRequestKey) throws ProviderException {
throwIfUnsupported(transactionsRequestKey);
if (transactionsRequestKey.hasKnownAddressTransactions()) {
return getCombined(transactionsRequestKey);
}
return getFromApi(transactionsRequestKey);
}

@Override
public boolean isSupported(TransactionsRequestKey key) {
return key.getChain() == BTC;
}

protected abstract Optional<AddressTransactions> getFromApi(TransactionsRequestKey transactionsRequestKey);

private Optional<AddressTransactions> getCombined(TransactionsRequestKey transactionsRequestKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@
import com.google.common.base.Preconditions;
import de.cotto.bitbook.backend.model.Address;
import de.cotto.bitbook.backend.model.AddressTransactions;
import de.cotto.bitbook.backend.model.Chain;

import java.util.Objects;

public class TransactionsRequestKey {
private final Address address;
private final Chain chain;
private final int blockHeight;
private final AddressTransactions addressTransactions;

public TransactionsRequestKey(Address address, int blockHeight) {
public TransactionsRequestKey(Address address, Chain chain, int blockHeight) {
this.address = address;
this.chain = chain;
this.blockHeight = blockHeight;
this.addressTransactions = AddressTransactions.UNKNOWN;
this.addressTransactions = AddressTransactions.unknown(chain);
}

public TransactionsRequestKey(AddressTransactions addressTransactions, int blockHeight) {
this.address = addressTransactions.getAddress();
this.chain = addressTransactions.getChain();
this.blockHeight = blockHeight;
this.addressTransactions = addressTransactions;
}
Expand All @@ -27,12 +31,16 @@ public Address getAddress() {
return address;
}

public Chain getChain() {
return chain;
}

public int getBlockHeight() {
return blockHeight;
}

public boolean hasKnownAddressTransactions() {
return !AddressTransactions.UNKNOWN.equals(addressTransactions);
return !AddressTransactions.unknown(addressTransactions.getChain()).equals(addressTransactions);
}

public AddressTransactions getAddressTransactions() {
Expand All @@ -50,13 +58,14 @@ public boolean equals(Object other) {
}
TransactionsRequestKey that = (TransactionsRequestKey) other;
return blockHeight == that.blockHeight
&& Objects.equals(chain, that.chain)
&& Objects.equals(address, that.address)
&& Objects.equals(addressTransactions, that.addressTransactions);
}

@Override
public int hashCode() {
return Objects.hash(address, blockHeight, addressTransactions);
return Objects.hash(address, chain, blockHeight, addressTransactions);
}

@Override
Expand All @@ -65,6 +74,7 @@ public String toString() {
"address='" + address + '\'' +
", addressTransactions='" + addressTransactions + '\'' +
", blockHeight=" + blockHeight +
", chain='" + chain + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import de.cotto.bitbook.backend.model.Address;
import de.cotto.bitbook.backend.model.AddressTransactions;
import de.cotto.bitbook.backend.model.Chain;
import de.cotto.bitbook.backend.model.TransactionHash;

import java.util.Set;
Expand All @@ -17,12 +18,13 @@ protected AddressTransactionsDto(Address address, Set<TransactionHash> transacti
this.transactionHashes = transactionHashes;
}

public AddressTransactions toModel(int lastCheckedAtBlockheight, Address expectedAddress) {
public AddressTransactions toModel(int lastCheckedAtBlockheight, Address expectedAddress, Chain chain) {
validateAddress(expectedAddress);
return new AddressTransactions(
requireNonNull(expectedAddress),
requireNonNull(transactionHashes),
lastCheckedAtBlockheight
lastCheckedAtBlockheight,
chain
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
import de.cotto.bitbook.backend.model.Address;
import org.junit.jupiter.api.Test;

import static de.cotto.bitbook.backend.model.AddressFixtures.ADDRESS;
import static de.cotto.bitbook.backend.model.Chain.BCH;
import static de.cotto.bitbook.backend.model.Chain.BTC;
import static de.cotto.bitbook.backend.model.TransactionFixtures.BLOCK_HEIGHT;
import static de.cotto.bitbook.backend.request.RequestPriority.LOWEST;
import static de.cotto.bitbook.backend.request.RequestPriority.STANDARD;
import static de.cotto.bitbook.backend.transaction.TransactionsRequestKeyFixtures.ADDRESS_TRANSACTIONS_LOWEST;
import static de.cotto.bitbook.backend.transaction.TransactionsRequestKeyFixtures.ADDRESS_TRANSACTIONS_REQUEST;
import static de.cotto.bitbook.backend.transaction.TransactionsRequestKeyFixtures.TRANSACTIONS_REQUEST_KEY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;

class AddressTransactionsRequestTest {
@Test
Expand Down Expand Up @@ -45,10 +49,18 @@ void testEquals_different_priority() {

@Test
void testEquals_different_address() {
TransactionsRequestKey key = new TransactionsRequestKey(new Address("xxx"), BLOCK_HEIGHT);
TransactionsRequestKey key = new TransactionsRequestKey(new Address("xxx"), BTC, BLOCK_HEIGHT);
assertThat(ADDRESS_TRANSACTIONS_REQUEST).isNotEqualTo(AddressTransactionsRequest.create(key, STANDARD));
}

@Test
void testEquals_different_chain() {
assumeThat(AddressTransactionsRequest.create(new TransactionsRequestKey(ADDRESS, BTC, BLOCK_HEIGHT), STANDARD))
.isEqualTo(ADDRESS_TRANSACTIONS_REQUEST);
assertThat(AddressTransactionsRequest.create(new TransactionsRequestKey(ADDRESS, BCH, BLOCK_HEIGHT), STANDARD))
.isNotEqualTo(ADDRESS_TRANSACTIONS_REQUEST);
}

@Test
void testToString() {
assertThat(ADDRESS_TRANSACTIONS_REQUEST).hasToString(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package de.cotto.bitbook.backend.transaction;

import de.cotto.bitbook.backend.model.Address;
import de.cotto.bitbook.backend.model.AddressTransactions;
import de.cotto.bitbook.backend.model.ProviderException;
import org.junit.jupiter.api.Test;

import javax.annotation.Nullable;
Expand All @@ -11,12 +13,16 @@
import static de.cotto.bitbook.backend.model.AddressTransactionsFixtures.ADDRESS_TRANSACTIONS;
import static de.cotto.bitbook.backend.model.AddressTransactionsFixtures.ADDRESS_TRANSACTIONS_UPDATED;
import static de.cotto.bitbook.backend.model.AddressTransactionsFixtures.LAST_CHECKED_AT_BLOCK_HEIGHT;
import static de.cotto.bitbook.backend.model.Chain.BCH;
import static de.cotto.bitbook.backend.model.Chain.BTC;
import static de.cotto.bitbook.backend.model.TransactionHashFixtures.TRANSACTION_HASH_3;
import static de.cotto.bitbook.backend.model.TransactionHashFixtures.TRANSACTION_HASH_4;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

class SimpleAddressTransactionsProviderTest {

private static final AddressTransactions UNKNOWN_BTC = AddressTransactions.unknown(BTC);
private final TestableAddressTransactionsProvider addressTransactionsProvider =
new TestableAddressTransactionsProvider();

Expand All @@ -26,40 +32,59 @@ void getName() {
}

@Test
void get_for_unknown_transactions() {
void get_for_unknown_transactions() throws Exception {
addressTransactionsProvider.apiResponse = ADDRESS_TRANSACTIONS;
Optional<AddressTransactions> addressTransactions =
addressTransactionsProvider.get(new TransactionsRequestKey(AddressTransactions.UNKNOWN, 123));
addressTransactionsProvider.get(new TransactionsRequestKey(UNKNOWN_BTC, 123));
assertThat(addressTransactions).contains(ADDRESS_TRANSACTIONS);
}

@Test
void updating_known_transactions() {
void updating_known_transactions() throws Exception {
addressTransactionsProvider.apiResponse = new AddressTransactions(
ADDRESS,
Set.of(TRANSACTION_HASH_3, TRANSACTION_HASH_4),
LAST_CHECKED_AT_BLOCK_HEIGHT + 50
LAST_CHECKED_AT_BLOCK_HEIGHT + 50,
BTC
);
TransactionsRequestKey request = new TransactionsRequestKey(ADDRESS_TRANSACTIONS, LAST_CHECKED_AT_BLOCK_HEIGHT);
Optional<AddressTransactions> addressTransactions = addressTransactionsProvider.get(request);
assertThat(addressTransactions).contains(ADDRESS_TRANSACTIONS_UPDATED);
}

@Test
void updating_with_unknown() {
addressTransactionsProvider.apiResponse = AddressTransactions.UNKNOWN;
void updating_with_unknown() throws Exception {
addressTransactionsProvider.apiResponse = UNKNOWN_BTC;
TransactionsRequestKey request = new TransactionsRequestKey(ADDRESS_TRANSACTIONS, LAST_CHECKED_AT_BLOCK_HEIGHT);
Optional<AddressTransactions> addressTransactions = addressTransactionsProvider.get(request);
assertThat(addressTransactions).contains(ADDRESS_TRANSACTIONS);
}

@Test
void no_response_from_api_when_updating() {
void no_response_from_api_when_updating() throws Exception {
TransactionsRequestKey request = new TransactionsRequestKey(ADDRESS_TRANSACTIONS, LAST_CHECKED_AT_BLOCK_HEIGHT);
Optional<AddressTransactions> addressTransactions = addressTransactionsProvider.get(request);
assertThat(addressTransactions).contains(ADDRESS_TRANSACTIONS);
}

@Test
void isSupported_btc() {
TransactionsRequestKey key = new TransactionsRequestKey(new Address("def"), BTC, 123);
assertThat(addressTransactionsProvider.isSupported(key)).isTrue();
}

@Test
void isSupported_bch() {
TransactionsRequestKey key = new TransactionsRequestKey(new Address("abc"), BCH, 123);
assertThat(addressTransactionsProvider.isSupported(key)).isFalse();
}

@Test
void get_unsupported() {
TransactionsRequestKey key = new TransactionsRequestKey(new Address("def"), BCH, 123);
assertThatExceptionOfType(ProviderException.class).isThrownBy(() -> addressTransactionsProvider.get(key));
}

private static class TestableAddressTransactionsProvider extends SimpleAddressTransactionsProvider {
@Nullable
public AddressTransactions apiResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import static de.cotto.bitbook.backend.model.AddressFixtures.ADDRESS;
import static de.cotto.bitbook.backend.model.AddressTransactionsFixtures.ADDRESS_TRANSACTIONS;
import static de.cotto.bitbook.backend.model.Chain.BTC;
import static de.cotto.bitbook.backend.model.TransactionFixtures.BLOCK_HEIGHT;
import static de.cotto.bitbook.backend.transaction.TransactionsRequestKeyFixtures.TRANSACTIONS_REQUEST_KEY;
import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -45,8 +46,9 @@ void testToString_without_transactions() {
assertThat(TRANSACTIONS_REQUEST_KEY).hasToString(
"TransactionsRequestKey{" +
"address='" + ADDRESS + "'" +
", addressTransactions='" + AddressTransactions.UNKNOWN + "'" +
", addressTransactions='" + AddressTransactions.unknown(BTC) + "'" +
", blockHeight=" + BLOCK_HEIGHT +
", chain='" + BTC + '\'' +
"}"
);
}
Expand All @@ -58,6 +60,7 @@ void testToString_with_transactions() {
"address='" + ADDRESS + "'" +
", addressTransactions='" + ADDRESS_TRANSACTIONS + "'" +
", blockHeight=" + BLOCK_HEIGHT +
", chain='" + BTC + '\'' +
"}"
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.Set;

import static de.cotto.bitbook.backend.model.AddressFixtures.ADDRESS_3;
import static de.cotto.bitbook.backend.model.Chain.BTC;
import static de.cotto.bitbook.backend.model.TransactionHashFixtures.TRANSACTION_HASH;
import static de.cotto.bitbook.backend.model.TransactionHashFixtures.TRANSACTION_HASH_2;
import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -18,16 +19,16 @@ void toModel() {
AddressTransactionsDto dto =
new AddressTransactionsDto(ADDRESS_3, Set.of(TRANSACTION_HASH, TRANSACTION_HASH_2));
AddressTransactions addressTransactions =
new AddressTransactions(ADDRESS_3, Set.of(TRANSACTION_HASH, TRANSACTION_HASH_2), 123);
assertThat(dto.toModel(123, ADDRESS_3)).isEqualTo(addressTransactions);
new AddressTransactions(ADDRESS_3, Set.of(TRANSACTION_HASH, TRANSACTION_HASH_2), 123, BTC);
assertThat(dto.toModel(123, ADDRESS_3, BTC)).isEqualTo(addressTransactions);
}

@Test
void toModel_invalid_address() {
AddressTransactionsDto dto =
new AddressTransactionsDto(ADDRESS_3, Set.of(TRANSACTION_HASH, TRANSACTION_HASH_2));
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> dto.toModel(123, new Address("def")));
.isThrownBy(() -> dto.toModel(123, new Address("def"), BTC));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package de.cotto.bitbook.backend.transaction;

import static de.cotto.bitbook.backend.model.AddressFixtures.ADDRESS;
import static de.cotto.bitbook.backend.model.Chain.BTC;
import static de.cotto.bitbook.backend.model.TransactionFixtures.BLOCK_HEIGHT;
import static de.cotto.bitbook.backend.request.RequestPriority.LOWEST;
import static de.cotto.bitbook.backend.request.RequestPriority.STANDARD;

public class TransactionsRequestKeyFixtures {
public static final TransactionsRequestKey TRANSACTIONS_REQUEST_KEY =
new TransactionsRequestKey(ADDRESS, BLOCK_HEIGHT);
new TransactionsRequestKey(ADDRESS, BTC, BLOCK_HEIGHT);
public static final AddressTransactionsRequest ADDRESS_TRANSACTIONS_REQUEST =
AddressTransactionsRequest.create(TRANSACTIONS_REQUEST_KEY, STANDARD);
public static final AddressTransactionsRequest ADDRESS_TRANSACTIONS_LOWEST =
Expand Down
1 change: 1 addition & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
implementation project(':backend:models')
runtimeOnly 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j'
runtimeOnly 'com.h2database:h2'
testImplementation testFixtures(project(':backend:models'))
}

jacocoTestCoverageVerification {
Expand Down
Loading

0 comments on commit 4892721

Please sign in to comment.