-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WIP] Annotations for pallets and their storages
- Loading branch information
Showing
41 changed files
with
1,108 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,18 @@ | ||
dependencies { | ||
implementation project(':rpc') | ||
implementation project(':rpc:rpc-core') | ||
implementation project(':rpc:rpc-sections') | ||
implementation project(':transport') | ||
implementation project(':pallet') | ||
implementation project(':scale') | ||
implementation project(':types') | ||
implementation project(':rpc:rpc-types') | ||
implementation project(':storage') | ||
|
||
testImplementation project(':tests') | ||
|
||
testImplementation 'org.testcontainers:testcontainers:1.16.3' | ||
testImplementation 'org.testcontainers:junit-jupiter:1.16.3' | ||
|
||
testAnnotationProcessor project(':pallet:pallet-codegen') | ||
} |
12 changes: 12 additions & 0 deletions
12
api/src/main/java/com/strategyobject/substrateclient/api/Api.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,19 @@ | ||
package com.strategyobject.substrateclient.api; | ||
|
||
import com.strategyobject.substrateclient.pallet.GeneratedPalletResolver; | ||
import com.strategyobject.substrateclient.rpc.Rpc; | ||
import com.strategyobject.substrateclient.rpc.RpcImpl; | ||
import com.strategyobject.substrateclient.transport.ProviderInterface; | ||
import lombok.val; | ||
|
||
public interface Api { | ||
static DefaultApi with(ProviderInterface provider) { | ||
val rpc = new RpcImpl(provider); | ||
|
||
return DefaultApi.with(rpc, GeneratedPalletResolver.with(rpc)); | ||
} | ||
|
||
Rpc getRpc(); | ||
|
||
<T> T pallet(Class<T> clazz); | ||
} |
29 changes: 29 additions & 0 deletions
29
api/src/main/java/com/strategyobject/substrateclient/api/DefaultApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.strategyobject.substrateclient.api; | ||
|
||
import com.strategyobject.substrateclient.pallet.PalletResolver; | ||
import com.strategyobject.substrateclient.rpc.Rpc; | ||
import lombok.NonNull; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor(staticName = "with") | ||
public class DefaultApi implements Api, AutoCloseable { | ||
private final @NonNull Rpc rpc; | ||
private final @NonNull PalletResolver palletResolver; | ||
|
||
@Override | ||
public Rpc getRpc() { | ||
return rpc; | ||
} | ||
|
||
@Override | ||
public <T> T pallet(@NonNull Class<T> clazz) { | ||
return palletResolver.resolve(clazz); | ||
} | ||
|
||
@Override | ||
public void close() throws Exception { | ||
if (rpc instanceof AutoCloseable) { | ||
((AutoCloseable) rpc).close(); | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.strategyobject.substrateclient.api; | ||
|
||
import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; | ||
import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; | ||
import com.strategyobject.substrateclient.transport.ws.WsProvider; | ||
import lombok.val; | ||
import org.junit.jupiter.api.Test; | ||
import org.testcontainers.junit.jupiter.Container; | ||
import org.testcontainers.junit.jupiter.Testcontainers; | ||
|
||
import java.math.BigInteger; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertNotEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
|
||
@Testcontainers | ||
public class ApiTests { | ||
private static final int WAIT_TIMEOUT = 1000; | ||
|
||
@Container | ||
private final TestSubstrateContainer substrate = new TestSubstrateContainer(SubstrateVersion.V3_0_0); | ||
|
||
@Test | ||
public void getSystemPalletAndCall() throws Exception { // TODO move the test out of the project | ||
val wsProvider = WsProvider.builder() | ||
.setEndpoint(substrate.getWsAddress()) | ||
.build(); | ||
wsProvider.connect().get(WAIT_TIMEOUT, TimeUnit.SECONDS); | ||
|
||
try (val api = Api.with(wsProvider)) { | ||
val systemPallet = api.pallet(SystemPallet.class); | ||
val blockHash = systemPallet | ||
.blockHash() | ||
.get(0) | ||
.get(WAIT_TIMEOUT, TimeUnit.SECONDS); | ||
|
||
assertNotNull(blockHash); | ||
assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.getData())); | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.strategyobject.substrateclient.api; | ||
|
||
import com.strategyobject.substrateclient.pallet.annotations.Pallet; | ||
import com.strategyobject.substrateclient.pallet.annotations.Storage; | ||
import com.strategyobject.substrateclient.pallet.annotations.StorageHasher; | ||
import com.strategyobject.substrateclient.pallet.annotations.StorageKey; | ||
import com.strategyobject.substrateclient.rpc.types.BlockHash; | ||
import com.strategyobject.substrateclient.scale.annotations.Scale; | ||
import com.strategyobject.substrateclient.storage.StorageNMap; | ||
|
||
@Pallet(name = "System") | ||
public interface SystemPallet { | ||
@Storage( | ||
name = "BlockHash", | ||
keys = { | ||
@StorageKey( | ||
type = @Scale(Integer.class), | ||
hasher = StorageHasher.TwoX64Concat | ||
) | ||
}) | ||
StorageNMap<BlockHash> blockHash(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
dependencies { | ||
implementation project(':scale') | ||
implementation project(':rpc') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
dependencies { | ||
implementation project(':common') | ||
implementation project(':rpc') | ||
implementation project(':types') | ||
implementation project(':scale') | ||
implementation project(':scale:scale-codegen') | ||
implementation project(':storage') | ||
implementation project(':pallet') | ||
|
||
implementation 'com.squareup:javapoet:1.13.0' | ||
|
||
compileOnly 'com.google.auto.service:auto-service-annotations:1.0.1' | ||
annotationProcessor 'com.google.auto.service:auto-service:1.0.1' | ||
|
||
testImplementation 'com.google.testing.compile:compile-testing:0.19' | ||
} |
32 changes: 32 additions & 0 deletions
32
...egen/src/main/java/com.strategyobject.substrateclient.pallet/CompoundMethodProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.strategyobject.substrateclient.pallet; | ||
|
||
import com.squareup.javapoet.MethodSpec; | ||
import com.squareup.javapoet.TypeSpec; | ||
import com.strategyobject.substrateclient.common.codegen.ProcessingException; | ||
import com.strategyobject.substrateclient.common.codegen.ProcessorContext; | ||
import lombok.NonNull; | ||
import lombok.var; | ||
|
||
import javax.lang.model.element.ExecutableElement; | ||
import javax.lang.model.element.TypeElement; | ||
import java.util.List; | ||
|
||
class CompoundMethodProcessor extends PalletMethodProcessor { | ||
private final List<PalletMethodProcessor> processors; | ||
|
||
public CompoundMethodProcessor(TypeElement typeElement, List<PalletMethodProcessor> processors) { | ||
super(typeElement); | ||
this.processors = processors; | ||
} | ||
|
||
@Override | ||
void process(@NonNull String palletName, @NonNull ExecutableElement method, TypeSpec.@NonNull Builder typeSpecBuilder, MethodSpec.Builder constructorBuilder, @NonNull ProcessorContext context) throws ProcessingException { | ||
for (var processor : processors) { | ||
processor.process(palletName, | ||
method, | ||
typeSpecBuilder, | ||
constructorBuilder, | ||
context); | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
pallet/pallet-codegen/src/main/java/com.strategyobject.substrateclient.pallet/Constants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.strategyobject.substrateclient.pallet; | ||
|
||
class Constants { | ||
static final String RPC = "rpc"; | ||
static final String CLASS_NAME_TEMPLATE = "%sImpl"; | ||
static final String SCALE_READER_REGISTRY = "scaleReaderRegistry"; | ||
static final String SCALE_WRITER_REGISTRY = "scaleWriterRegistry"; | ||
static final String STORAGE_FACTORY_METHOD = "with"; | ||
static final String STORAGE_KEY_PROVIDER_FACTORY_METHOD = "of"; | ||
static final String STORAGE_KEY_PROVIDER_ADD_HASHERS = "use"; | ||
static final String KEY_HASHER_FACTORY_METHOD = "with"; | ||
static final String BLAKE_2_128_CONCAT_INSTANCE = "getInstance"; | ||
static final String TWO_X64_CONCAT_INSTANCE = "getInstance"; | ||
static final String IDENTITY_FACTORY_METHOD = "sizeOf"; | ||
} |
83 changes: 83 additions & 0 deletions
83
...gen/src/main/java/com.strategyobject.substrateclient.pallet/PalletAnnotatedInterface.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package com.strategyobject.substrateclient.pallet; | ||
|
||
import com.google.common.base.Strings; | ||
import com.squareup.javapoet.JavaFile; | ||
import com.squareup.javapoet.MethodSpec; | ||
import com.squareup.javapoet.TypeName; | ||
import com.squareup.javapoet.TypeSpec; | ||
import com.strategyobject.substrateclient.common.codegen.ProcessingException; | ||
import com.strategyobject.substrateclient.common.codegen.ProcessorContext; | ||
import com.strategyobject.substrateclient.pallet.annotations.Pallet; | ||
import com.strategyobject.substrateclient.rpc.Rpc; | ||
import lombok.val; | ||
|
||
import javax.lang.model.element.ExecutableElement; | ||
import javax.lang.model.element.Modifier; | ||
import javax.lang.model.element.TypeElement; | ||
import java.io.IOException; | ||
|
||
import static com.strategyobject.substrateclient.pallet.Constants.CLASS_NAME_TEMPLATE; | ||
import static com.strategyobject.substrateclient.pallet.Constants.RPC; | ||
|
||
public class PalletAnnotatedInterface { | ||
private final TypeElement interfaceElement; | ||
private final String name; | ||
private final PalletMethodProcessor methodProcessor; | ||
|
||
public PalletAnnotatedInterface(TypeElement interfaceElement, PalletMethodProcessor methodProcessor) throws ProcessingException { | ||
this.interfaceElement = interfaceElement; | ||
val annotation = interfaceElement.getAnnotation(Pallet.class); | ||
|
||
if (!interfaceElement.getModifiers().contains(Modifier.PUBLIC)) { | ||
throw new ProcessingException( | ||
interfaceElement, | ||
"`%s` is not public. That is not allowed.", | ||
interfaceElement.getQualifiedName().toString()); | ||
} | ||
|
||
if (Strings.isNullOrEmpty(name = annotation.name())) { | ||
throw new ProcessingException( | ||
interfaceElement, | ||
"`@%s` of `%s` contains null or empty `name`.", | ||
annotation.getClass().getSimpleName(), | ||
interfaceElement.getQualifiedName().toString()); | ||
} | ||
|
||
this.methodProcessor = methodProcessor; | ||
} | ||
|
||
public void generateClass(ProcessorContext context) throws ProcessingException, IOException { | ||
val interfaceName = interfaceElement.getSimpleName().toString(); | ||
val className = String.format(CLASS_NAME_TEMPLATE, interfaceName); | ||
val packageName = context.getPackageName(interfaceElement); | ||
|
||
val typeSpecBuilder = TypeSpec.classBuilder(className) | ||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL) | ||
.addSuperinterface(TypeName.get(interfaceElement.asType())) | ||
.addField(Rpc.class, RPC, Modifier.FINAL, Modifier.PRIVATE); | ||
|
||
val constructorBuilder = createConstructorBuilder(); | ||
|
||
for (val method : interfaceElement.getEnclosedElements()) { | ||
this.methodProcessor.process(name, | ||
(ExecutableElement) method, | ||
typeSpecBuilder, | ||
constructorBuilder, | ||
context); | ||
} | ||
|
||
typeSpecBuilder.addMethod(constructorBuilder.build()); | ||
|
||
JavaFile.builder(packageName, typeSpecBuilder.build()).build().writeTo(context.getFiler()); | ||
} | ||
|
||
private MethodSpec.Builder createConstructorBuilder() { | ||
return MethodSpec.constructorBuilder() | ||
.addModifiers(Modifier.PUBLIC) | ||
.addParameter(Rpc.class, RPC) | ||
.beginControlFlow("if ($L == null)", RPC) | ||
.addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, RPC) | ||
.endControlFlow() | ||
.addStatement("this.$1L = $1L", RPC); | ||
} | ||
} |
Oops, something went wrong.