Skip to content

Commit 62b9e68

Browse files
committed
add MetadataProvider
1 parent 6a2d6e7 commit 62b9e68

File tree

34 files changed

+440
-134
lines changed

34 files changed

+440
-134
lines changed

api/src/main/java/com/strategyobject/substrateclient/api/Api.java

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.inject.Module;
44
import com.strategyobject.substrateclient.pallet.PalletFactory;
55
import com.strategyobject.substrateclient.rpc.RpcSectionFactory;
6+
import com.strategyobject.substrateclient.rpc.metadata.MetadataProvider;
67
import com.strategyobject.substrateclient.transport.ProviderInterface;
78
import lombok.NonNull;
89
import lombok.RequiredArgsConstructor;
@@ -20,6 +21,7 @@
2021
public class Api implements AutoCloseable {
2122
private final @NonNull RpcSectionFactory rpcSectionFactory;
2223
private final @NonNull PalletFactory palletFactory;
24+
private final @NonNull MetadataProvider metadataProvider;
2325
private final Map<Class<?>, Object> resolvedCache = new ConcurrentHashMap<>();
2426

2527

@@ -45,6 +47,15 @@ public <T> T pallet(@NonNull Class<T> clazz) {
4547
return clazz.cast(resolvedCache.computeIfAbsent(clazz, palletFactory::create));
4648
}
4749

50+
/**
51+
* Provides access to current version of metadata in use.
52+
*
53+
* @return MetadataProvider instance
54+
*/
55+
public MetadataProvider metadata() {
56+
return metadataProvider;
57+
}
58+
4859
@Override
4960
public void close() throws Exception {
5061
if (rpcSectionFactory instanceof AutoCloseable) {

api/src/main/java/com/strategyobject/substrateclient/api/DefaultModule.java

+85-18
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@
33
import com.google.inject.AbstractModule;
44
import com.google.inject.Provides;
55
import com.google.inject.Singleton;
6-
import com.strategyobject.substrateclient.common.types.AutoRegistry;
6+
import com.strategyobject.substrateclient.crypto.ss58.SS58AddressFormat;
77
import com.strategyobject.substrateclient.pallet.GeneratedPalletFactory;
88
import com.strategyobject.substrateclient.pallet.PalletFactory;
99
import com.strategyobject.substrateclient.rpc.GeneratedRpcSectionFactory;
1010
import com.strategyobject.substrateclient.rpc.RpcSectionFactory;
1111
import com.strategyobject.substrateclient.rpc.api.section.State;
12+
import com.strategyobject.substrateclient.rpc.context.RpcDecoderContext;
13+
import com.strategyobject.substrateclient.rpc.context.RpcDecoderContextFactory;
14+
import com.strategyobject.substrateclient.rpc.context.RpcEncoderContext;
15+
import com.strategyobject.substrateclient.rpc.context.RpcEncoderContextFactory;
16+
import com.strategyobject.substrateclient.rpc.metadata.ManualMetadataProvider;
17+
import com.strategyobject.substrateclient.rpc.metadata.MetadataProvider;
18+
import com.strategyobject.substrateclient.rpc.metadata.Pallet;
19+
import com.strategyobject.substrateclient.rpc.metadata.PalletCollection;
1220
import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry;
1321
import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry;
1422
import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry;
@@ -18,20 +26,21 @@
1826
import lombok.RequiredArgsConstructor;
1927
import lombok.val;
2028

29+
import java.util.function.BiConsumer;
2130
import java.util.function.Consumer;
2231

2332
@RequiredArgsConstructor
2433
public class DefaultModule extends AbstractModule {
25-
private final @NonNull ProviderInterface providerInterface;
34+
private static final String PREFIX = "com.strategyobject.substrateclient";
2635

27-
private Consumer<ScaleReaderRegistry> configureScaleReaderRegistry = this::autoRegister;
28-
private Consumer<ScaleWriterRegistry> configureScaleWriterRegistry = this::autoRegister;
29-
private Consumer<RpcDecoderRegistry> configureRpcDecoderRegistry = this::autoRegister;
30-
private Consumer<RpcEncoderRegistry> configureRpcEncoderRegistry = this::autoRegister;
36+
private final @NonNull ProviderInterface providerInterface;
3137

32-
private void autoRegister(AutoRegistry registry) {
33-
registry.registerAnnotatedFrom("com.strategyobject.substrateclient");
34-
}
38+
private Consumer<ScaleReaderRegistry> configureScaleReaderRegistry = x -> x.registerAnnotatedFrom(PREFIX);
39+
private Consumer<ScaleWriterRegistry> configureScaleWriterRegistry = x -> x.registerAnnotatedFrom(PREFIX);
40+
private BiConsumer<RpcDecoderRegistry, RpcDecoderContextFactory> configureRpcDecoderRegistry =
41+
(registry, contextFactory) -> registry.registerAnnotatedFrom(contextFactory, PREFIX);
42+
private BiConsumer<RpcEncoderRegistry, RpcEncoderContextFactory> configureRpcEncoderRegistry =
43+
(registry, contextFactory) -> registry.registerAnnotatedFrom(contextFactory, PREFIX);
3544

3645
public DefaultModule configureScaleReaderRegistry(Consumer<ScaleReaderRegistry> configure) {
3746
configureScaleReaderRegistry = configureScaleReaderRegistry.andThen(configure);
@@ -43,12 +52,12 @@ public DefaultModule configureScaleWriterRegistry(Consumer<ScaleWriterRegistry>
4352
return this;
4453
}
4554

46-
public DefaultModule configureRpcDecoderRegistry(Consumer<RpcDecoderRegistry> configure) {
55+
public DefaultModule configureRpcDecoderRegistry(BiConsumer<RpcDecoderRegistry, RpcDecoderContextFactory> configure) {
4756
configureRpcDecoderRegistry = configureRpcDecoderRegistry.andThen(configure);
4857
return this;
4958
}
5059

51-
public DefaultModule configureRpcEncoderRegistry(Consumer<RpcEncoderRegistry> configure) {
60+
public DefaultModule configureRpcEncoderRegistry(BiConsumer<RpcEncoderRegistry, RpcEncoderContextFactory> configure) {
5261
configureRpcEncoderRegistry = configureRpcEncoderRegistry.andThen(configure);
5362
return this;
5463
}
@@ -78,7 +87,8 @@ protected void configure() {
7887
.toConstructor(
7988
Api.class.getConstructor(
8089
RpcSectionFactory.class,
81-
PalletFactory.class))
90+
PalletFactory.class,
91+
MetadataProvider.class))
8292
.asEagerSingleton();
8393
} catch (NoSuchMethodException e) {
8494
throw new RuntimeException(e);
@@ -103,20 +113,77 @@ public ScaleWriterRegistry provideScaleWriterRegistry() {
103113

104114
@Provides
105115
@Singleton
106-
public RpcDecoderRegistry provideRpcDecoderRegistry(ScaleReaderRegistry scaleReaderRegistry) {
107-
val registry = new RpcDecoderRegistry(scaleReaderRegistry);
108-
configureRpcDecoderRegistry.accept(registry);
116+
public RpcDecoderRegistry provideRpcDecoderRegistry(MetadataProvider metadataProvider,
117+
ScaleReaderRegistry scaleReaderRegistry) {
118+
val registry = new RpcDecoderRegistry();
119+
val context = new RpcDecoderContext(
120+
metadataProvider,
121+
registry,
122+
scaleReaderRegistry);
123+
124+
configureRpcDecoderRegistry.accept(registry, () -> context);
109125
return registry;
110126
}
111127

112128
@Provides
113129
@Singleton
114-
public RpcEncoderRegistry provideRpcEncoderRegistry(ScaleWriterRegistry scaleWriterRegistry) {
115-
val registry = new RpcEncoderRegistry(scaleWriterRegistry);
116-
configureRpcEncoderRegistry.accept(registry);
130+
public RpcEncoderRegistry provideRpcEncoderRegistry(MetadataProvider metadataProvider,
131+
ScaleWriterRegistry scaleWriterRegistry) {
132+
val registry = new RpcEncoderRegistry();
133+
val context = new RpcEncoderContext(
134+
metadataProvider,
135+
registry,
136+
scaleWriterRegistry);
137+
138+
configureRpcEncoderRegistry.accept(registry, () -> context);
117139
return registry;
118140
}
119141

142+
@Provides
143+
@Singleton
144+
public MetadataProvider provideMetadata() {
145+
// TODO. Use provider based on real Metadata
146+
return new ManualMetadataProvider(
147+
SS58AddressFormat.SUBSTRATE_ACCOUNT,
148+
new PalletCollection(
149+
new Pallet(0, "System"),
150+
new Pallet(1, "Utility"),
151+
new Pallet(2, "Babe"),
152+
new Pallet(3, "Timestamp"),
153+
new Pallet(4, "Authorship"),
154+
new Pallet(5, "Indices"),
155+
new Pallet(6, "Balances"),
156+
new Pallet(7, "TransactionPayment"),
157+
new Pallet(8, "Staking"),
158+
new Pallet(9, "Session"),
159+
new Pallet(10, "Democracy"),
160+
new Pallet(11, "Council"),
161+
new Pallet(12, "TechnicalCommittee"),
162+
new Pallet(13, "Elections"),
163+
new Pallet(14, "TechnicalMembership"),
164+
new Pallet(15, "Grandpa"),
165+
new Pallet(16, "Treasury"),
166+
new Pallet(17, "Contracts"),
167+
new Pallet(18, "Sudo"),
168+
new Pallet(19, "ImOnline"),
169+
new Pallet(20, "AuthorityDiscovery"),
170+
new Pallet(21, "Offences"),
171+
new Pallet(22, "Historical"),
172+
new Pallet(23, "RandomnessCollectiveFlip"),
173+
new Pallet(24, "Identity"),
174+
new Pallet(25, "Society"),
175+
new Pallet(26, "Recovery"),
176+
new Pallet(27, "Vesting"),
177+
new Pallet(28, "Scheduler"),
178+
new Pallet(29, "Proxy"),
179+
new Pallet(30, "Multisig"),
180+
new Pallet(31, "Bounties"),
181+
new Pallet(32, "Tips"),
182+
new Pallet(33, "Assets"),
183+
new Pallet(34, "Mmr"),
184+
new Pallet(35, "Lottery")));
185+
}
186+
120187
@Provides
121188
@Singleton
122189
public State provideState(RpcSectionFactory rpcSectionFactory) {

api/src/main/java/com/strategyobject/substrateclient/api/RequireModule.java

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.inject.AbstractModule;
44
import com.strategyobject.substrateclient.pallet.PalletFactory;
55
import com.strategyobject.substrateclient.rpc.RpcSectionFactory;
6+
import com.strategyobject.substrateclient.rpc.metadata.MetadataProvider;
67
import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry;
78
import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry;
89
import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry;
@@ -17,6 +18,7 @@ protected void configure() {
1718
requireBinding(ScaleWriterRegistry.class);
1819
requireBinding(RpcDecoderRegistry.class);
1920
requireBinding(RpcEncoderRegistry.class);
21+
requireBinding(MetadataProvider.class);
2022
requireBinding(RpcSectionFactory.class);
2123
requireBinding(PalletFactory.class);
2224
requireBinding(Api.class);

api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java api/src/test/java/com/strategyobject/substrateclient/api/ApiTest.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.inject.CreationException;
44
import com.google.inject.util.Modules;
55
import com.strategyobject.substrateclient.common.convert.HexConverter;
6+
import com.strategyobject.substrateclient.crypto.ss58.SS58AddressFormat;
67
import com.strategyobject.substrateclient.pallet.PalletFactory;
78
import com.strategyobject.substrateclient.rpc.api.AccountId;
89
import com.strategyobject.substrateclient.rpc.api.BlockNumber;
@@ -24,7 +25,7 @@
2425
import static org.mockito.Mockito.verify;
2526

2627
@Testcontainers
27-
class ApiTests {
28+
class ApiTest {
2829
private static final int WAIT_TIMEOUT = 1000;
2930

3031
@Container
@@ -61,6 +62,19 @@ void getSystemSectionAndCall() throws Exception {
6162
}
6263
}
6364

65+
@Test
66+
void getSS58AddressFormat() throws Exception {
67+
val wsProvider = WsProvider.builder()
68+
.setEndpoint(substrate.getWsAddress());
69+
70+
try (val api = Api.with(wsProvider).build().join()) {
71+
val ss58AddressFormat = api.metadata().getSS58AddressFormat();
72+
73+
assertNotNull(ss58AddressFormat);
74+
assertEquals(SS58AddressFormat.SUBSTRATE_ACCOUNT, ss58AddressFormat);
75+
}
76+
}
77+
6478
@Test
6579
void configureApi() throws Exception {
6680
val wsProvider = WsProvider.builder()
@@ -69,10 +83,8 @@ void configureApi() throws Exception {
6983
val expected = mock(Index.class);
7084
try (val api = Api.with(wsProvider)
7185
.configure(defaultModule ->
72-
defaultModule.configureRpcDecoderRegistry(registry ->
73-
registry.register(
74-
(value, decoders) -> expected,
75-
Index.class)))
86+
defaultModule.configureRpcDecoderRegistry((registry, _factory) ->
87+
registry.register((value, decoders) -> expected, Index.class)))
7688
.build()
7789
.join()) {
7890
val system = api.rpc(System.class);

common/src/main/java/com/strategyobject/substrateclient/common/types/AutoRegistry.java

-5
This file was deleted.

crypto/src/main/java/com/strategyobject/substrateclient/crypto/ss58/AddressWithPrefix.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
@Getter
1111
public class AddressWithPrefix {
1212
private final byte @NonNull [] address;
13-
private final short prefix;
13+
private final SS58AddressFormat prefix;
1414
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.strategyobject.substrateclient.crypto.ss58;
2+
3+
import lombok.EqualsAndHashCode;
4+
import lombok.Getter;
5+
import lombok.RequiredArgsConstructor;
6+
7+
@Getter
8+
@RequiredArgsConstructor(staticName = "of")
9+
@EqualsAndHashCode
10+
public class SS58AddressFormat {
11+
private final short prefix;
12+
13+
/**
14+
* Polkadot Relay-chain, standard account (*25519).
15+
*/
16+
public static final SS58AddressFormat POLKADOT_ACCOUNT = new SS58AddressFormat((short) 0);
17+
18+
/**
19+
* Bare 32-bit Schnorr/Ristretto 25519 (S/R 25519) key.
20+
*/
21+
public static final SS58AddressFormat BARE_SR_25519 = new SS58AddressFormat((short) 1);
22+
23+
/**
24+
* Bare 32-bit Edwards Ed25519 key.
25+
*/
26+
public static final SS58AddressFormat KUSAMA_ACCOUNT = new SS58AddressFormat((short) 2);
27+
28+
/**
29+
* Any Substrate network, standard account (*25519).
30+
*/
31+
public static final SS58AddressFormat BARE_ED_25519 = new SS58AddressFormat((short) 3);
32+
33+
/**
34+
* Any Substrate network, standard account (*25519).
35+
*/
36+
public static final SS58AddressFormat SUBSTRATE_ACCOUNT = new SS58AddressFormat((short) 42);
37+
}

crypto/src/main/java/com/strategyobject/substrateclient/crypto/ss58/SS58Codec.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,17 @@ public static AddressWithPrefix decode(@NonNull String encoded) {
5353
throw new IllegalArgumentException("Incorrect checksum.");
5454
}
5555

56-
return AddressWithPrefix.from(Arrays.copyOfRange(data, typeLen, typeLen + ADDRESS_LENGTH), prefix);
56+
return AddressWithPrefix.from(
57+
Arrays.copyOfRange(data, typeLen, typeLen + ADDRESS_LENGTH),
58+
SS58AddressFormat.of(prefix));
5759
}
5860

59-
public static String encode(byte @NonNull [] address, short prefix) {
61+
public static String encode(byte @NonNull [] address, SS58AddressFormat prefix) {
6062
Preconditions.checkArgument(address.length == ADDRESS_LENGTH,
6163
"The length of address must be 32, but was: " + address.length);
6264

63-
val ident = prefix & 0b0011_1111_1111_1111;
64-
Preconditions.checkArgument(ident == prefix,
65+
val ident = prefix.getPrefix() & 0b0011_1111_1111_1111;
66+
Preconditions.checkArgument(ident == prefix.getPrefix(),
6567
"The prefix size is restricted by 14 bits.");
6668

6769
byte[] data;

crypto/src/test/java/com/strategyobject/substrateclient/crypto/ss58/SS58CodecTests.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class SS58CodecTests {
2020
},
2121
delimiterString = ":")
2222
void encode(String expected, String hex, short prefix) {
23-
val actual = SS58Codec.encode(HexConverter.toBytes(hex), prefix);
23+
val actual = SS58Codec.encode(HexConverter.toBytes(hex), SS58AddressFormat.of(prefix));
2424

2525
assertEquals(expected, actual);
2626
}
@@ -33,7 +33,9 @@ void encode(String expected, String hex, short prefix) {
3333
},
3434
delimiterString = ":")
3535
void encodeThrows(String hex, short prefix) {
36-
assertThrows(IllegalArgumentException.class, () -> SS58Codec.encode(HexConverter.toBytes(hex), prefix));
36+
val format = SS58AddressFormat.of(prefix);
37+
val address = HexConverter.toBytes(hex);
38+
assertThrows(IllegalArgumentException.class, () -> SS58Codec.encode(address, format));
3739
}
3840

3941
@ParameterizedTest
@@ -49,7 +51,7 @@ void encodeThrows(String hex, short prefix) {
4951
void decode(String source, String hex, short prefix) {
5052
val actual = SS58Codec.decode(source);
5153

52-
val expected = AddressWithPrefix.from(HexConverter.toBytes(hex), prefix);
54+
val expected = AddressWithPrefix.from(HexConverter.toBytes(hex), SS58AddressFormat.of(prefix));
5355
assertEquals(expected, actual);
5456
}
5557

0 commit comments

Comments
 (0)