Skip to content

Commit b3dcc57

Browse files
Merge pull request #148 from OpenElements/network-provider
Provide Settings for Hiero Networks by "Plug and Play"
2 parents f840833 + 335606f commit b3dcc57

File tree

35 files changed

+612
-232
lines changed

35 files changed

+612
-232
lines changed

.github/workflows/maven.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ jobs:
4141
spring_profiles_active: solo
4242
HEDERA_ACCOUNT_ID: ${{ steps.solo.outputs.accountId }}
4343
HEDERA_PRIVATE_KEY: ${{ steps.solo.outputs.privateKey }}
44-
HEDERA_NETWORK: solo
44+
HEDERA_NETWORK: hiero-solo-action
4545
run: ./mvnw verify
4646

hiero-enterprise-base/pom.xml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,21 @@
3737
<artifactId>jspecify</artifactId>
3838
<scope>compile</scope>
3939
</dependency>
40+
<dependency>
41+
<groupId>com.google.auto.service</groupId>
42+
<artifactId>auto-service-annotations</artifactId>
43+
<scope>compile</scope>
44+
</dependency>
4045
<dependency>
4146
<groupId>org.junit.jupiter</groupId>
4247
<artifactId>junit-jupiter</artifactId>
4348
<scope>test</scope>
4449
</dependency>
4550
<dependency>
46-
<groupId>org.mockito</groupId>
47-
<artifactId>mockito-core</artifactId>
48-
<scope>test</scope>
49-
</dependency>
51+
<groupId>org.mockito</groupId>
52+
<artifactId>mockito-core</artifactId>
53+
<scope>test</scope>
54+
</dependency>
5055
<dependency>
5156
<groupId>io.grpc</groupId>
5257
<artifactId>grpc-okhttp</artifactId>

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: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.openelements.hiero.base.config;
2+
3+
import com.openelements.hiero.base.config.implementation.NetworkSettingsProviderLoader;
4+
import java.util.Optional;
5+
import java.util.Set;
6+
import org.jspecify.annotations.NonNull;
7+
8+
/**
9+
* Interface that provides all needed configuration settings for a network. Operator of a Hiero based network should
10+
* implement this interface to provide the necessary configuration settings. Implementations can be provided via Java
11+
* SPI as defined in {@link NetworkSettingsProvider}.
12+
*
13+
* @see NetworkSettingsProvider
14+
* @see java.util.ServiceLoader
15+
*/
16+
public interface NetworkSettings {
17+
18+
/**
19+
* Returns the network identifier.
20+
*
21+
* @return the network identifier
22+
*/
23+
@NonNull
24+
String getNetworkIdentifier();
25+
26+
/**
27+
* Returns the network name.
28+
*
29+
* @return the network name
30+
*/
31+
@NonNull
32+
Optional<String> getNetworkName();
33+
34+
/**
35+
* Returns the mirror node addresses.
36+
*
37+
* @return the mirror node addresses
38+
*/
39+
@NonNull
40+
Set<String> getMirrorNodeAddresses();
41+
42+
/**
43+
* Returns the consensus nodes.
44+
*
45+
* @return the consensus nodes
46+
*/
47+
@NonNull
48+
Set<ConsensusNode> getConsensusNodes();
49+
50+
/**
51+
* Returns the chain ID of the network.
52+
*
53+
* @return the chain ID of the network
54+
*/
55+
@NonNull
56+
Optional<Long> chainId();
57+
58+
/**
59+
* Returns the relay URL of the network.
60+
*
61+
* @return the relay URL of the network.
62+
*/
63+
@NonNull
64+
Optional<String> relayUrl();
65+
66+
/**
67+
* Returns all available network settings.
68+
*
69+
* @return all available network settings
70+
*/
71+
static Set<NetworkSettings> all() {
72+
return NetworkSettingsProviderLoader.getInstance().all();
73+
}
74+
75+
/**
76+
* Returns the network settings for the given identifier.
77+
*
78+
* @param identifier the identifier of the network
79+
* @return the network settings for the given identifier
80+
*/
81+
static Optional<NetworkSettings> forIdentifier(String identifier) {
82+
return NetworkSettingsProviderLoader.getInstance().forIdentifier(identifier);
83+
}
84+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.openelements.hiero.base.config;
2+
3+
import java.util.Set;
4+
5+
/**
6+
* SPI interface to provide predefined {@link NetworkSettings} instances. Java SPI functionality is documented at
7+
* {@link java.util.ServiceLoader}.
8+
*/
9+
public interface NetworkSettingsProvider {
10+
11+
/**
12+
* Returns the name of the provider.
13+
*
14+
* @return the name of the provider
15+
*/
16+
String getName();
17+
18+
/**
19+
* Return a set of {@link NetworkSettings} instances provided by this provider.
20+
*
21+
* @return a set of {@link NetworkSettings} instances
22+
*/
23+
Set<NetworkSettings> createNetworkSettings();
24+
}
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.hedera;
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:443");
26+
}
27+
28+
@Override
29+
public @NonNull Set<ConsensusNode> getConsensusNodes() {
30+
return Set.of(new ConsensusNode("35.186.191.247", "50211", "0.0.4"));
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.hedera;
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:443");
26+
}
27+
28+
@Override
29+
public @NonNull Set<ConsensusNode> getConsensusNodes() {
30+
return Set.of(new ConsensusNode("0.testnet.hedera.com", "50211", "0.0.3"));
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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.openelements.hiero.base.config.hedera;
2+
3+
import com.google.auto.service.AutoService;
4+
import com.openelements.hiero.base.config.NetworkSettings;
5+
import com.openelements.hiero.base.config.NetworkSettingsProvider;
6+
import java.util.Set;
7+
8+
@AutoService(NetworkSettingsProvider.class)
9+
public final class HederaNetworkSettingsProvider implements NetworkSettingsProvider {
10+
11+
@Override
12+
public String getName() {
13+
return "Hedera";
14+
}
15+
16+
@Override
17+
public Set<NetworkSettings> createNetworkSettings() {
18+
return Set.of(new HederMainnetSettings(), new HederTestnetSettings());
19+
}
20+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.openelements.hiero.base.config.implementation;
2+
3+
import com.openelements.hiero.base.config.NetworkSettings;
4+
import com.openelements.hiero.base.config.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)