Skip to content

Commit 872024a

Browse files
committed
Support custom network configs by SPI provider
Signed-off-by: Hendrik Ebbers <[email protected]>
1 parent f840833 commit 872024a

File tree

16 files changed

+391
-185
lines changed

16 files changed

+391
-185
lines changed

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/config/HieroConfig.java

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.hedera.hashgraph.sdk.Client;
55
import com.openelements.hiero.base.HieroContext;
66
import com.openelements.hiero.base.data.Account;
7-
import com.openelements.hiero.base.implementation.HieroNetwork;
87
import java.util.List;
98
import java.util.Map;
109
import java.util.Optional;
@@ -43,7 +42,7 @@ public interface HieroConfig {
4342
* @return the mirror node addresses
4443
*/
4544
@NonNull
46-
List<String> getMirrorNodeAddresses();
45+
Set<String> getMirrorNodeAddresses();
4746

4847
/**
4948
* Returns the consensus nodes.
@@ -53,13 +52,11 @@ public interface HieroConfig {
5352
@NonNull
5453
Set<ConsensusNode> getConsensusNodes();
5554

56-
/**
57-
* Returns the network.
58-
*
59-
* @return
60-
*/
6155
@NonNull
62-
HieroNetwork getNetwork();
56+
Optional<Long> chainId();
57+
58+
@NonNull
59+
Optional<String> relayUrl();
6360

6461
/**
6562
* Creates a Hiero context. Calling this method multiple times will return a new instance each time.
@@ -90,31 +87,16 @@ default HieroContext createHieroContext() {
9087
*/
9188
@NonNull
9289
default Client createClient() {
93-
final HieroNetwork hieroNetwork = getNetwork();
94-
if (hieroNetwork != HieroNetwork.CUSTOM) {
95-
try {
96-
log.debug("Hiero network '{}' will be used", hieroNetwork.getName());
97-
98-
//TODO: Hack since the Client is still Hedera specific and not migrated to Hiero
99-
Client client = Client.forName(hieroNetwork.getName().substring("hedera-".length()));
100-
client.setOperator(getOperatorAccount().accountId(), getOperatorAccount().privateKey());
101-
return client;
102-
} catch (Exception e) {
103-
throw new IllegalArgumentException("Can not create client for network " + hieroNetwork.getName(),
104-
e);
105-
}
106-
} else {
107-
try {
108-
final Map<String, AccountId> nodes = getConsensusNodes().stream()
109-
.collect(Collectors.toMap(n -> n.getAddress(), n -> n.getAccountId()));
110-
final Client client = Client.forNetwork(nodes);
111-
client.setMirrorNetwork(getMirrorNodeAddresses());
112-
client.setOperator(getOperatorAccount().accountId(), getOperatorAccount().privateKey());
113-
return client;
114-
} catch (Exception e) {
115-
throw new IllegalArgumentException("Can not create client for custom network", e);
116-
}
90+
try {
91+
final Map<String, AccountId> nodes = getConsensusNodes().stream()
92+
.collect(Collectors.toMap(n -> n.getAddress(), n -> n.getAccountId()));
93+
final Client client = Client.forNetwork(nodes);
94+
final List<String> mirrorNodeAddresses = getMirrorNodeAddresses().stream().collect(Collectors.toList());
95+
client.setMirrorNetwork(mirrorNodeAddresses);
96+
client.setOperator(getOperatorAccount().accountId(), getOperatorAccount().privateKey());
97+
return client;
98+
} catch (Exception e) {
99+
throw new IllegalArgumentException("Can not create client for custom network", e);
117100
}
118101
}
119-
120102
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.openelements.hiero.base.config;
2+
3+
import com.openelements.hiero.base.config.provider.implementation.NetworkSettingsProviderLoader;
4+
import java.util.Optional;
5+
import java.util.Set;
6+
import org.jspecify.annotations.NonNull;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
public interface NetworkSettings {
11+
12+
Logger logger = LoggerFactory.getLogger(NetworkSettings.class);
13+
14+
/**
15+
* Returns the network identifier.
16+
*
17+
* @return the network identifier
18+
*/
19+
@NonNull
20+
String getNetworkIdentifier();
21+
22+
/**
23+
* Returns the network name.
24+
*
25+
* @return the network name
26+
*/
27+
@NonNull
28+
Optional<String> getNetworkName();
29+
30+
/**
31+
* Returns the mirror node addresses.
32+
*
33+
* @return the mirror node addresses
34+
*/
35+
@NonNull
36+
Set<String> getMirrorNodeAddresses();
37+
38+
/**
39+
* Returns the consensus nodes.
40+
*
41+
* @return the consensus nodes
42+
*/
43+
@NonNull
44+
Set<ConsensusNode> getConsensusNodes();
45+
46+
@NonNull
47+
Optional<Long> chainId();
48+
49+
@NonNull
50+
Optional<String> relayUrl();
51+
52+
static Set<NetworkSettings> all() {
53+
return NetworkSettingsProviderLoader.getInstance().all();
54+
}
55+
56+
static Optional<NetworkSettings> forIdentifier(String identifier) {
57+
return NetworkSettingsProviderLoader.getInstance().forIdentifier(identifier);
58+
}
59+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.openelements.hiero.base.config.provider;
2+
3+
import com.openelements.hiero.base.config.ConsensusNode;
4+
import com.openelements.hiero.base.config.NetworkSettings;
5+
import java.util.Optional;
6+
import java.util.Set;
7+
import org.jspecify.annotations.NonNull;
8+
9+
public final class HederMainnetSettings implements NetworkSettings {
10+
11+
public static final String NETWORK_IDENTIFIER = "hedera-mainnet";
12+
13+
@Override
14+
public @NonNull String getNetworkIdentifier() {
15+
return NETWORK_IDENTIFIER;
16+
}
17+
18+
@Override
19+
public @NonNull Optional<String> getNetworkName() {
20+
return Optional.of("Hedera Mainnet");
21+
}
22+
23+
@Override
24+
public @NonNull Set<String> getMirrorNodeAddresses() {
25+
return Set.of("https://mainnet.mirrornode.hedera.com/");
26+
}
27+
28+
@Override
29+
public @NonNull Set<ConsensusNode> getConsensusNodes() {
30+
return Set.of();
31+
}
32+
33+
@Override
34+
public @NonNull Optional<Long> chainId() {
35+
return Optional.of(295L);
36+
}
37+
38+
@Override
39+
public @NonNull Optional<String> relayUrl() {
40+
return Optional.of("https://mainnet.hashio.io/api");
41+
}
42+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.openelements.hiero.base.config.provider;
2+
3+
import com.openelements.hiero.base.config.ConsensusNode;
4+
import com.openelements.hiero.base.config.NetworkSettings;
5+
import java.util.Optional;
6+
import java.util.Set;
7+
import org.jspecify.annotations.NonNull;
8+
9+
public final class HederPreviewnetSettings implements NetworkSettings {
10+
11+
public static final String NETWORK_IDENTIFIER = "hedera-previewnet";
12+
13+
@Override
14+
public @NonNull String getNetworkIdentifier() {
15+
return NETWORK_IDENTIFIER;
16+
}
17+
18+
@Override
19+
public @NonNull Optional<String> getNetworkName() {
20+
return Optional.of("Hedera Previewnet");
21+
}
22+
23+
@Override
24+
public @NonNull Set<String> getMirrorNodeAddresses() {
25+
return Set.of("https://previewnet.mirrornode.hedera.com/");
26+
}
27+
28+
@Override
29+
public @NonNull Set<ConsensusNode> getConsensusNodes() {
30+
return Set.of();
31+
}
32+
33+
@Override
34+
public @NonNull Optional<Long> chainId() {
35+
return Optional.of(297L);
36+
}
37+
38+
@Override
39+
public @NonNull Optional<String> relayUrl() {
40+
return Optional.of("https://previewnet.hashio.io/api");
41+
}
42+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.openelements.hiero.base.config.provider;
2+
3+
import com.openelements.hiero.base.config.ConsensusNode;
4+
import com.openelements.hiero.base.config.NetworkSettings;
5+
import java.util.Optional;
6+
import java.util.Set;
7+
import org.jspecify.annotations.NonNull;
8+
9+
public final class HederTestnetSettings implements NetworkSettings {
10+
11+
public static final String NETWORK_IDENTIFIER = "hedera-testnet";
12+
13+
@Override
14+
public @NonNull String getNetworkIdentifier() {
15+
return NETWORK_IDENTIFIER;
16+
}
17+
18+
@Override
19+
public @NonNull Optional<String> getNetworkName() {
20+
return Optional.of("Hedera Testnet");
21+
}
22+
23+
@Override
24+
public @NonNull Set<String> getMirrorNodeAddresses() {
25+
return Set.of("https://testnet.mirrornode.hedera.com/");
26+
}
27+
28+
@Override
29+
public @NonNull Set<ConsensusNode> getConsensusNodes() {
30+
return Set.of();
31+
}
32+
33+
@Override
34+
public @NonNull Optional<Long> chainId() {
35+
return Optional.of(296L);
36+
}
37+
38+
@Override
39+
public @NonNull Optional<String> relayUrl() {
40+
return Optional.of("https://testnet.hashio.io/api");
41+
}
42+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.openelements.hiero.base.config.provider;
2+
3+
import com.openelements.hiero.base.config.NetworkSettings;
4+
import java.util.Set;
5+
6+
public interface NetworkSettingsProvider {
7+
8+
String getName();
9+
10+
Set<NetworkSettings> createNetworkSettings();
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.openelements.hiero.base.config.provider.implementation;
2+
3+
import com.openelements.hiero.base.config.NetworkSettings;
4+
import com.openelements.hiero.base.config.provider.HederMainnetSettings;
5+
import com.openelements.hiero.base.config.provider.NetworkSettingsProvider;
6+
import java.util.Set;
7+
8+
public final class HederaNetworkSettingsProvider implements NetworkSettingsProvider {
9+
10+
@Override
11+
public String getName() {
12+
return "Hedera";
13+
}
14+
15+
@Override
16+
public Set<NetworkSettings> createNetworkSettings() {
17+
return Set.of(new HederMainnetSettings());
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.openelements.hiero.base.config.provider.implementation;
2+
3+
import com.openelements.hiero.base.config.NetworkSettings;
4+
import com.openelements.hiero.base.config.provider.NetworkSettingsProvider;
5+
import java.util.Collections;
6+
import java.util.HashSet;
7+
import java.util.Objects;
8+
import java.util.Optional;
9+
import java.util.ServiceLoader;
10+
import java.util.Set;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
14+
public final class NetworkSettingsProviderLoader {
15+
16+
private final static Logger logger = LoggerFactory.getLogger(NetworkSettingsProviderLoader.class);
17+
18+
private final static NetworkSettingsProviderLoader instance = new NetworkSettingsProviderLoader();
19+
20+
private final Set<NetworkSettings> settings;
21+
22+
private NetworkSettingsProviderLoader() {
23+
final Set<NetworkSettings> loaded = new HashSet<>();
24+
ServiceLoader<NetworkSettingsProvider> loader = ServiceLoader.load(NetworkSettingsProvider.class);
25+
loader.stream().forEach(provider -> {
26+
final NetworkSettingsProvider networkSettingsProvider = provider.get();
27+
logger.info("Loading network settings from provider: {}", networkSettingsProvider.getName());
28+
final Set<NetworkSettings> networkSettingsFromProvider = networkSettingsProvider.createNetworkSettings();
29+
logger.debug("Loaded {} network settings from provider {}", networkSettingsFromProvider.size(),
30+
networkSettingsProvider.getName());
31+
networkSettingsFromProvider.forEach(setting -> {
32+
if (loaded.stream().anyMatch(
33+
existing -> Objects.equals(existing.getNetworkIdentifier(), setting.getNetworkIdentifier()))) {
34+
throw new IllegalStateException(
35+
"Network settings with identifier " + setting.getNetworkIdentifier() + " already loaded");
36+
} else {
37+
loaded.add(setting);
38+
}
39+
});
40+
});
41+
this.settings = Collections.unmodifiableSet(loaded);
42+
}
43+
44+
public Set<NetworkSettings> all() {
45+
return settings;
46+
}
47+
48+
public Optional<NetworkSettings> forIdentifier(String identifier) {
49+
return all().stream().filter(settings -> Objects.equals(settings.getNetworkIdentifier(), identifier))
50+
.findFirst();
51+
}
52+
53+
public static NetworkSettingsProviderLoader getInstance() {
54+
return instance;
55+
}
56+
}

0 commit comments

Comments
 (0)