From 438f0ea9f8bca442a6d44fcf4542ce2075fa2798 Mon Sep 17 00:00:00 2001 From: Alexander Kalankhodzhaev Date: Sat, 11 Jun 2022 11:06:40 +0700 Subject: [PATCH] revise rpc api types --- .../substrateclient/api/ApiTests.java | 3 +- .../substrateclient/api/SystemPallet.java | 3 +- .../substrateclient/common/types/Bytes.java | 6 + .../common/types/FixedBytes.java | 2 +- .../pallet/storage/StorageNMapImpl.java | 2 +- .../pallet/storage/IdentityTests.java | 3 +- .../pallet/storage/KeyHasherTests.java | 5 +- .../pallet/storage/StorageNMapImplTests.java | 60 +++--- .../pallet/storage/StorageValueImplTests.java | 3 +- .../substrateclient/rpc/api/BlockHash.java | 16 +- .../rpc/api/BlockHashReader.java | 21 -- .../substrateclient/rpc/api/BlockNumber.java | 21 ++ ...erDecoder.java => BlockNumberDecoder.java} | 8 +- .../rpc/api/BlockNumberEncoder.java | 14 ++ .../rpc/api/BlockNumberU32Reader.java | 24 +++ .../rpc/api/BlockNumberU32Writer.java | 23 +++ .../substrateclient/rpc/api/BytesDecoder.java | 16 ++ .../substrateclient/rpc/api/BytesEncoder.java | 25 +++ .../substrateclient/rpc/api/Extrinsic.java | 1 - .../rpc/api/ExtrinsicWriter.java | 18 +- .../rpc/api/FixedBytesWriter.java | 4 +- .../substrateclient/rpc/api/Hash.java | 15 +- .../substrateclient/rpc/api/HashReader.java | 21 -- .../substrateclient/rpc/api/Header.java | 3 +- .../substrateclient/rpc/api/Index.java | 26 +++ .../substrateclient/rpc/api/IndexDecoder.java | 14 ++ .../substrateclient/rpc/api/Number.java | 12 -- .../substrateclient/rpc/api/SignedExtra.java | 3 +- .../rpc/api/StorageChangeSet.java | 2 - .../substrateclient/rpc/api/impl/Hash256.java | 18 ++ .../rpc/api/impl/Hash256Decoder.java | 17 ++ .../rpc/api/impl/Hash256Reader.java | 23 +++ .../rpc/api/section/Author.java | 42 +++- .../rpc/api/section/Chain.java | 56 ++++- .../rpc/api/section/State.java | 193 +++++++++++++++--- .../rpc/api/section/System.java | 12 +- .../rpc/api/section/AuthorTests.java | 6 +- .../rpc/api/section/ChainTests.java | 33 ++- .../rpc/api/section/StateTests.java | 7 +- .../rpc/api/section/SystemTests.java | 4 +- .../reader/ScaleReaderAnnotatedClass.java | 2 +- .../writer/ScaleWriterAnnotatedClass.java | 2 +- 42 files changed, 599 insertions(+), 190 deletions(-) create mode 100644 common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java delete mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHashReader.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java rename rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/{NumberDecoder.java => BlockNumberDecoder.java} (67%) create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberEncoder.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java delete mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/HashReader.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/IndexDecoder.java delete mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Number.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java create mode 100644 rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Reader.java diff --git a/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java b/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java index 7dd24fc9..ace57ff1 100644 --- a/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java +++ b/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java @@ -1,5 +1,6 @@ package com.strategyobject.substrateclient.api; +import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -32,7 +33,7 @@ void getSystemPalletAndCall() throws Exception { // TODO move the test out of th val systemPallet = api.pallet(SystemPallet.class); val blockHash = systemPallet .blockHash() - .get(0) + .get(BlockNumber.GENESIS) .get(WAIT_TIMEOUT, TimeUnit.SECONDS); assertNotNull(blockHash); diff --git a/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java b/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java index e2b4e725..9b23591d 100644 --- a/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java +++ b/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java @@ -6,6 +6,7 @@ import com.strategyobject.substrateclient.pallet.annotation.StorageKey; import com.strategyobject.substrateclient.pallet.storage.StorageNMap; import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.scale.annotation.Scale; @Pallet("System") @@ -14,7 +15,7 @@ public interface SystemPallet { value = "BlockHash", keys = { @StorageKey( - type = @Scale(Integer.class), + type = @Scale(BlockNumber.class), hasher = StorageHasher.TWOX_64_CONCAT ) }) diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java b/common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java new file mode 100644 index 00000000..26922321 --- /dev/null +++ b/common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java @@ -0,0 +1,6 @@ +package com.strategyobject.substrateclient.common.types; + +@FunctionalInterface +public interface Bytes { + byte[] getData(); +} diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java b/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java index 75f8ff5d..ce044169 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java @@ -5,7 +5,7 @@ import lombok.Getter; @EqualsAndHashCode -public abstract class FixedBytes implements Fixed { +public abstract class FixedBytes implements Fixed, Bytes { @Getter private final byte[] data; diff --git a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImpl.java b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImpl.java index 71de6472..a7553ebc 100644 --- a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImpl.java +++ b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImpl.java @@ -3,8 +3,8 @@ import com.strategyobject.substrateclient.common.types.tuple.Pair; import com.strategyobject.substrateclient.rpc.api.BlockHash; import com.strategyobject.substrateclient.rpc.api.Hash; -import com.strategyobject.substrateclient.rpc.api.section.State; import com.strategyobject.substrateclient.rpc.api.StorageKey; +import com.strategyobject.substrateclient.rpc.api.section.State; import com.strategyobject.substrateclient.scale.ScaleReader; import lombok.NonNull; import lombok.RequiredArgsConstructor; diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java index 507e4a5c..11304829 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java @@ -1,6 +1,7 @@ package com.strategyobject.substrateclient.pallet.storage; import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.impl.Hash256; import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.SneakyThrows; @@ -19,7 +20,7 @@ class IdentityTests { private static Stream getTestCasesForGetHash() { return Stream.of( encode(Integer.class, -175), - encode(BlockHash.class, BlockHash.fromBytes(random(32))), + encode(BlockHash.class, Hash256.fromBytes(random(32))), "TestString".getBytes(StandardCharsets.UTF_8), random(new Random().nextInt(128) + 1)); } diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java index bba7c717..03b6b7aa 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java @@ -4,6 +4,7 @@ import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.impl.Hash256; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.scale.readers.CompactIntegerReader; @@ -44,7 +45,7 @@ private static Stream getTestCasesForGetHash() { "0x4f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48" ), Arguments.of( - BlockHash.fromBytes(HexConverter.toBytes("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")), + Hash256.fromBytes(HexConverter.toBytes("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")), ScaleReaderRegistry.getInstance().resolve(BlockHash.class), ScaleWriterRegistry.getInstance().resolve(BlockHash.class), Identity.getInstance(), @@ -115,7 +116,7 @@ private static Stream getTestCasesForExtractKey() { ScaleReaderRegistry.getInstance().resolve(BlockHash.class), ScaleWriterRegistry.getInstance().resolve(BlockHash.class), Identity.getInstance(), - BlockHash.fromBytes(HexConverter.toBytes("0xabcdef98765432100123456789abcdefabcdef98765432100123456789abcdef")), + Hash256.fromBytes(HexConverter.toBytes("0xabcdef98765432100123456789abcdefabcdef98765432100123456789abcdef")), 0 ), Arguments.of( diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java index edc730b5..638f8732 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java @@ -5,6 +5,7 @@ import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.rpc.api.section.Chain; import com.strategyobject.substrateclient.rpc.api.section.State; import com.strategyobject.substrateclient.scale.ScaleReader; @@ -48,8 +49,8 @@ private static StorageNMapImpl newSystemBlockHashStorage(State state) state, (ScaleReader) ScaleReaderRegistry.getInstance().resolve(BlockHash.class), StorageKeyProvider.of("System", "BlockHash") - .use(KeyHasher.with((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(Integer.class), - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(Integer.class), + .use(KeyHasher.with((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(BlockNumber.class), + (ScaleReader) ScaleReaderRegistry.getInstance().resolve(BlockNumber.class), TwoX64Concat.getInstance()))); } @@ -74,10 +75,10 @@ void keys() throws Exception { assertNotNull(collection); assertEquals(1, collection.size()); - val blockNumber = new AtomicReference(null); - collection.iterator().forEachRemaining(q -> q.consume((o -> blockNumber.set((Integer) o.get(0))))); + val blockNumber = new AtomicReference(null); + collection.iterator().forEachRemaining(q -> q.consume((o -> blockNumber.set((BlockNumber) o.get(0))))); - assertEquals(0, blockNumber.get()); + assertEquals(BlockNumber.GENESIS, blockNumber.get()); val blocks = collection.multi().execute().get(); val list = new ArrayList<>(); @@ -101,7 +102,7 @@ void multiToDifferentStorages() throws Exception { val storageMap = newSystemBlockHashStorage(state); val getKey = storageValue.query(); - val getHash = storageMap.query(0); + val getHash = storageMap.query(BlockNumber.GENESIS); val multi = getKey.join(getHash); val collection = multi.execute().get(); @@ -110,7 +111,7 @@ void multiToDifferentStorages() throws Exception { SS58Codec.decode( "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") .getAddress()); - val expectedBlock = storageMap.get(0).get(); + val expectedBlock = storageMap.get(BlockNumber.GENESIS).get(); val list = new ArrayList<>(2); collection.iterator().forEachRemaining(e -> e.consume((value, keys) -> list.add(value))); @@ -130,14 +131,14 @@ void entries() throws Exception { assertNotNull(collection); - val blockNumber = new AtomicReference(null); + val blockNumber = new AtomicReference(null); val blockHash = new AtomicReference(null); collection.iterator().forEachRemaining(e -> e.consume((value, keys) -> { blockHash.set(value); - blockNumber.set((Integer) keys.get(0)); + blockNumber.set((BlockNumber) keys.get(0)); })); - assertEquals(0, blockNumber.get()); + assertEquals(BlockNumber.GENESIS, blockNumber.get()); assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.get().getData())); } } @@ -148,18 +149,24 @@ void multi() throws Exception { val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); val storage = newSystemBlockHashStorage(state); - val collection = storage.multi(Arg.of(0), Arg.of(1)).get(); + val collection = storage.multi( + Arg.of(BlockNumber.GENESIS), + Arg.of(BlockNumber.of(1))) + .get(); assertNotNull(collection); - val list = new ArrayList>(); - collection.iterator().forEachRemaining(e -> e.consume((value, keys) -> list.add(Pair.of((Integer) keys.get(0), value)))); + val list = new ArrayList>(); + collection.iterator() + .forEachRemaining(e -> + e.consume((value, keys) -> + list.add(Pair.of((BlockNumber) keys.get(0), value)))); assertEquals(2, list.size()); - assertEquals(0, list.get(0).getValue0()); + assertEquals(BlockNumber.GENESIS, list.get(0).getValue0()); assertNotEquals(BigInteger.ZERO, new BigInteger(list.get(0).getValue1().getData())); - assertEquals(1, list.get(1).getValue0()); + assertEquals(BlockNumber.of(1), list.get(1).getValue0()); assertNull(list.get(1).getValue1()); } } @@ -204,14 +211,17 @@ void entriesPaged() throws Exception { assertNotNull(pages); var pageCount = 0; - val pairs = new ArrayList>(); + val pairs = new ArrayList>(); while (pages.moveNext().join()) { - pages.current().iterator().forEachRemaining(e -> e.consume((value, keys) -> { - val key = (Integer) keys.get(0); - assertNotEquals(BigInteger.ZERO, new BigInteger(value.getData())); - - pairs.add(Pair.of(key, value)); - })); + pages.current() + .iterator() + .forEachRemaining(e -> + e.consume((value, keys) -> { + val key = (BlockNumber) keys.get(0); + assertNotEquals(BigInteger.ZERO, new BigInteger(value.getData())); + + pairs.add(Pair.of(key, value)); + })); pageCount++; assertEquals(pageCount, pages.number()); } @@ -227,16 +237,16 @@ void entriesPaged() throws Exception { void subscribe() throws Exception { try (val wsProvider = getConnectedProvider()) { val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); - val blockNumber = 2; + val blockNumber = BlockNumber.of(2); val storage = newSystemBlockHashStorage(state); val blockHash = new AtomicReference(); val value = new AtomicReference(); - val argument = new AtomicInteger(); + val argument = new AtomicReference(); val unsubscribe = storage.subscribe((exception, block, v, keys) -> { if (exception == null) { blockHash.set(block); value.set(v); - argument.set((Integer) keys.get(0)); + argument.set((BlockNumber) keys.get(0)); } }, Arg.of(blockNumber)) .get(WAIT_TIMEOUT, TimeUnit.SECONDS); diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java index a2f5b07a..c933faf6 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java @@ -3,6 +3,7 @@ import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; import com.strategyobject.substrateclient.rpc.api.AccountId; +import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.rpc.api.section.Chain; import com.strategyobject.substrateclient.rpc.api.section.State; import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; @@ -64,7 +65,7 @@ void sudoKeyAtGenesis() throws Exception { val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); - val blockHash = chain.getBlockHash(0).get(); + val blockHash = chain.getBlockHash(BlockNumber.GENESIS).get(); val storage = StorageValueImpl.with( state, ScaleReaderRegistry.getInstance().resolve(AccountId.class), diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHash.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHash.java index 02dde2a1..60e5568b 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHash.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHash.java @@ -1,18 +1,4 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.common.types.FixedBytes; -import com.strategyobject.substrateclient.common.types.Size; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; -import lombok.NonNull; - -public class BlockHash - extends FixedBytes - implements ScaleSelfWritable { - protected BlockHash(byte[] data) { - super(data, Size.of32); - } - - public static BlockHash fromBytes(byte @NonNull [] data) { - return new BlockHash(data); - } +public interface BlockHash extends Hash { } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHashReader.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHashReader.java deleted file mode 100644 index 529c7e08..00000000 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockHashReader.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.strategyobject.substrateclient.rpc.api; - -import com.google.common.base.Preconditions; -import com.strategyobject.substrateclient.common.io.Streamer; -import com.strategyobject.substrateclient.common.types.Size; -import com.strategyobject.substrateclient.scale.ScaleReader; -import com.strategyobject.substrateclient.scale.annotation.AutoRegister; -import lombok.NonNull; - -import java.io.IOException; -import java.io.InputStream; - -@AutoRegister(types = BlockHash.class) -public class BlockHashReader implements ScaleReader { - @Override - public BlockHash read(@NonNull InputStream stream, ScaleReader... readers) throws IOException { - Preconditions.checkArgument(readers == null || readers.length == 0); - - return BlockHash.fromBytes(Streamer.readBytes(Size.of32.getValue(), stream)); - } -} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java new file mode 100644 index 00000000..e0dc0cc3 --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java @@ -0,0 +1,21 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.strategyobject.substrateclient.scale.ScaleSelfWritable; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.math.BigInteger; + +@RequiredArgsConstructor(staticName = "of") +@Getter +@EqualsAndHashCode +public class BlockNumber implements ScaleSelfWritable { + public static final BlockNumber GENESIS = BlockNumber.of(BigInteger.ZERO); + + private final BigInteger value; + + public static BlockNumber of(long value) { + return of(BigInteger.valueOf(value)); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/NumberDecoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberDecoder.java similarity index 67% rename from rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/NumberDecoder.java rename to rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberDecoder.java index 51da418d..2a69cc92 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/NumberDecoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberDecoder.java @@ -8,13 +8,13 @@ import java.math.BigInteger; -@AutoRegister(types = Number.class) -public class NumberDecoder extends AbstractDecoder { +@AutoRegister(types = BlockNumber.class) +public class BlockNumberDecoder extends AbstractDecoder { @Override - protected Number decodeNonNull(RpcObject value, DecoderPair[] decoders) { + protected BlockNumber decodeNonNull(RpcObject value, DecoderPair[] decoders) { val stringValue = value.asString(); val number = new BigInteger(stringValue.substring(2), 16); - return Number.of(number); + return BlockNumber.of(number); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberEncoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberEncoder.java new file mode 100644 index 00000000..622f65cf --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberEncoder.java @@ -0,0 +1,14 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.strategyobject.substrateclient.rpc.EncoderPair; +import com.strategyobject.substrateclient.rpc.RpcEncoder; +import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; + +@AutoRegister(types = BlockNumber.class) +public class BlockNumberEncoder implements RpcEncoder { + + @Override + public Object encode(BlockNumber source, EncoderPair... encoders) { + return "0x" + source.getValue().toString(16); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java new file mode 100644 index 00000000..f434a580 --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java @@ -0,0 +1,24 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.google.common.base.Preconditions; +import com.strategyobject.substrateclient.scale.ScaleReader; +import com.strategyobject.substrateclient.scale.ScaleType; +import com.strategyobject.substrateclient.scale.annotation.AutoRegister; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import lombok.NonNull; +import lombok.val; + +import java.io.IOException; +import java.io.InputStream; + +@AutoRegister(types = BlockNumber.class) +public class BlockNumberU32Reader implements ScaleReader { + @SuppressWarnings("unchecked") + @Override + public BlockNumber read(@NonNull InputStream stream, ScaleReader... readers) throws IOException { + Preconditions.checkArgument(readers == null || readers.length == 0); + + val u32Reader = (ScaleReader) ScaleReaderRegistry.getInstance().resolve(ScaleType.U32.class); + return BlockNumber.of(u32Reader.read(stream)); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java new file mode 100644 index 00000000..0faf830f --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java @@ -0,0 +1,23 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.google.common.base.Preconditions; +import com.strategyobject.substrateclient.scale.ScaleType; +import com.strategyobject.substrateclient.scale.ScaleWriter; +import com.strategyobject.substrateclient.scale.annotation.AutoRegister; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import lombok.NonNull; + +import java.io.IOException; +import java.io.OutputStream; + +@AutoRegister(types = BlockNumber.class) +public class BlockNumberU32Writer implements ScaleWriter { + @SuppressWarnings("unchecked") + @Override + public void write(@NonNull BlockNumber value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { + Preconditions.checkArgument(writers == null || writers.length == 0); + + ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(ScaleType.U32.class)) + .write(value.getValue().longValue(), stream); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java new file mode 100644 index 00000000..0f594cc9 --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java @@ -0,0 +1,16 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.strategyobject.substrateclient.common.types.Bytes; +import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.rpc.DecoderPair; +import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; +import com.strategyobject.substrateclient.rpc.decoders.AbstractDecoder; +import com.strategyobject.substrateclient.transport.RpcObject; + +@AutoRegister(types = Bytes.class) +public class BytesDecoder extends AbstractDecoder { + @Override + protected Bytes decodeNonNull(RpcObject value, DecoderPair[] decoders) { + return () -> HexConverter.toBytes(value.asString()); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java new file mode 100644 index 00000000..3d4a06f2 --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java @@ -0,0 +1,25 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.google.common.base.Preconditions; +import com.strategyobject.substrateclient.common.types.Bytes; +import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.rpc.EncoderPair; +import com.strategyobject.substrateclient.rpc.RpcEncoder; +import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; +import com.strategyobject.substrateclient.rpc.api.impl.Hash256; + +@AutoRegister( + types = { + Bytes.class, + Hash256.class, + Hash.class, + BlockHash.class + }) +public class BytesEncoder implements RpcEncoder { + @Override + public Object encode(Bytes source, EncoderPair... encoders) { + Preconditions.checkArgument(encoders == null || encoders.length == 0); + + return HexConverter.toHex(source.getData()); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java index 9f02c008..65ca3798 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java @@ -5,7 +5,6 @@ import java.util.Optional; -// ScaleWriter must be overridden. It must be represented in hex string as a byte array of scale. @Getter public class Extrinsic implements ScaleSelfWritable> { diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java index e0ddc766..c83ff061 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java @@ -11,35 +11,39 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.Optional; @AutoRegister(types = Extrinsic.class) -public class ExtrinsicWriter implements ScaleWriter> { +public class ExtrinsicWriter + implements ScaleWriter> { private static final int VERSION = 4; @Override - public void write(@NonNull Extrinsic value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { + public void write(@NonNull Extrinsic value, + @NonNull OutputStream stream, + ScaleWriter... writers) throws IOException { Preconditions.checkArgument(writers == null || writers.length == 0); val encodedExtrinsic = new ByteArrayOutputStream(); writeExtrinsic(value, encodedExtrinsic); - wrapToVec(encodedExtrinsic, stream); } @SuppressWarnings("unchecked") private void wrapToVec(ByteArrayOutputStream encodedExtrinsic, OutputStream stream) throws IOException { - ((ScaleWriter)ScaleWriterRegistry.getInstance().resolve(ScaleType.CompactInteger.class)) + ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(ScaleType.CompactInteger.class)) .write(encodedExtrinsic.size(), stream); stream.write(encodedExtrinsic.toByteArray()); } @SuppressWarnings("unchecked") - private void writeExtrinsic(Extrinsic value, ByteArrayOutputStream stream) throws IOException { + private void writeExtrinsic(Extrinsic value, ByteArrayOutputStream stream) throws IOException { val u8Writer = (ScaleWriter) ScaleWriterRegistry.getInstance().resolve(ScaleType.U8.class); - if (value.getSignature().isPresent()) { + val maybeSignature = value.getSignature(); + if (maybeSignature.isPresent()) { u8Writer.write(VERSION | 0b1000_0000, stream); - val signature = (SignaturePayload) value.getSignature().get(); + val signature = maybeSignature.get(); signature.write(stream); } else { u8Writer.write(VERSION & 0b0111_1111, stream); diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java index 113d47bb..0cc50cf1 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java @@ -6,6 +6,7 @@ import com.strategyobject.substrateclient.common.types.Size; import com.strategyobject.substrateclient.crypto.PublicKey; import com.strategyobject.substrateclient.crypto.SignatureData; +import com.strategyobject.substrateclient.rpc.api.impl.Hash256; import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import lombok.NonNull; @@ -16,8 +17,9 @@ @AutoRegister( types = { AccountId.class, - BlockHash.class, + Hash256.class, Hash.class, + BlockHash.class, PublicKey.class, SignatureData.class }) diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java index 21b6f651..150db0a6 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java @@ -1,16 +1,7 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.common.types.FixedBytes; -import com.strategyobject.substrateclient.common.types.Size; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; -import lombok.NonNull; +import com.strategyobject.substrateclient.common.types.Bytes; -public class Hash extends FixedBytes implements ScaleSelfWritable { - private Hash(byte[] data) { - super(data, Size.of32); - } - - public static Hash fromBytes(byte @NonNull [] data) { - return new Hash(data); - } +public interface Hash extends Bytes { + byte[] getData(); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/HashReader.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/HashReader.java deleted file mode 100644 index da73f71e..00000000 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/HashReader.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.strategyobject.substrateclient.rpc.api; - -import com.google.common.base.Preconditions; -import com.strategyobject.substrateclient.common.io.Streamer; -import com.strategyobject.substrateclient.common.types.Size; -import com.strategyobject.substrateclient.scale.ScaleReader; -import com.strategyobject.substrateclient.scale.annotation.AutoRegister; -import lombok.NonNull; - -import java.io.IOException; -import java.io.InputStream; - -@AutoRegister(types = Hash.class) -public class HashReader implements ScaleReader { - @Override - public Hash read(@NonNull InputStream stream, ScaleReader... readers) throws IOException { - Preconditions.checkArgument(readers == null || readers.length == 0); - - return Hash.fromBytes(Streamer.readBytes(Size.of32.getValue(), stream)); - } -} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Header.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Header.java index f4f71598..5ffe7dff 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Header.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Header.java @@ -12,6 +12,5 @@ public class Header { // TODO add rest fields @Scale private BlockHash parentHash; - private Number number; /* TODO probably it would be better to change the type to BigInteger - and support specific decoders */ + private BlockNumber number; } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java new file mode 100644 index 00000000..f99a1569 --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java @@ -0,0 +1,26 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.strategyobject.substrateclient.scale.ScaleSelfWritable; +import com.strategyobject.substrateclient.scale.ScaleType; +import com.strategyobject.substrateclient.scale.annotation.Scale; +import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.math.BigInteger; + +@RequiredArgsConstructor(staticName = "of") +@Getter +@EqualsAndHashCode +@ScaleWriter +public class Index implements ScaleSelfWritable { + public static final Index ZERO = Index.of(BigInteger.ZERO); + + @Scale(ScaleType.CompactBigInteger.class) + private final BigInteger value; + + public static Index of(long value) { + return of(BigInteger.valueOf(value)); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/IndexDecoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/IndexDecoder.java new file mode 100644 index 00000000..112f879f --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/IndexDecoder.java @@ -0,0 +1,14 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.strategyobject.substrateclient.rpc.DecoderPair; +import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; +import com.strategyobject.substrateclient.rpc.decoders.AbstractDecoder; +import com.strategyobject.substrateclient.transport.RpcObject; + +@AutoRegister(types = Index.class) +public class IndexDecoder extends AbstractDecoder { + @Override + protected Index decodeNonNull(RpcObject value, DecoderPair[] decoders) { + return Index.of(value.asNumber().longValue()); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Number.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Number.java deleted file mode 100644 index fa92bad3..00000000 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Number.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.strategyobject.substrateclient.rpc.api; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.math.BigInteger; - -@RequiredArgsConstructor(staticName = "of") -@Getter -public class Number { - private final BigInteger value; -} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java index 3cd27646..07267f00 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java @@ -22,8 +22,7 @@ public class SignedExtra implements Extra, SignedExtension { @Ignore private final BlockHash eraBlock; private final E era; - @Scale(ScaleType.CompactBigInteger.class) - private final BigInteger nonce; + private final Index nonce; @Scale(ScaleType.CompactBigInteger.class) private final BigInteger tip; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageChangeSet.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageChangeSet.java index 638e620d..708f6da6 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageChangeSet.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageChangeSet.java @@ -4,13 +4,11 @@ import com.strategyobject.substrateclient.rpc.annotation.RpcDecoder; import com.strategyobject.substrateclient.scale.annotation.Scale; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import java.util.List; @RpcDecoder -@NoArgsConstructor @Getter @Setter public class StorageChangeSet { diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java new file mode 100644 index 00000000..e7becf6a --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java @@ -0,0 +1,18 @@ +package com.strategyobject.substrateclient.rpc.api.impl; + +import com.strategyobject.substrateclient.common.types.FixedBytes; +import com.strategyobject.substrateclient.common.types.Size; +import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.Hash; +import com.strategyobject.substrateclient.scale.ScaleSelfWritable; +import lombok.NonNull; + +public class Hash256 extends FixedBytes implements Hash, BlockHash, ScaleSelfWritable { + private Hash256(byte[] data) { + super(data, Size.of32); + } + + public static Hash256 fromBytes(byte @NonNull [] data) { + return new Hash256(data); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java new file mode 100644 index 00000000..bcbee317 --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java @@ -0,0 +1,17 @@ +package com.strategyobject.substrateclient.rpc.api.impl; + +import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.rpc.DecoderPair; +import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; +import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.Hash; +import com.strategyobject.substrateclient.rpc.decoders.AbstractDecoder; +import com.strategyobject.substrateclient.transport.RpcObject; + +@AutoRegister(types = {Hash256.class, Hash.class, BlockHash.class}) +public class Hash256Decoder extends AbstractDecoder { + @Override + protected Hash256 decodeNonNull(RpcObject value, DecoderPair[] decoders) { + return Hash256.fromBytes(HexConverter.toBytes(value.asString())); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Reader.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Reader.java new file mode 100644 index 00000000..67c6a08e --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Reader.java @@ -0,0 +1,23 @@ +package com.strategyobject.substrateclient.rpc.api.impl; + +import com.google.common.base.Preconditions; +import com.strategyobject.substrateclient.common.io.Streamer; +import com.strategyobject.substrateclient.common.types.Size; +import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.Hash; +import com.strategyobject.substrateclient.scale.ScaleReader; +import com.strategyobject.substrateclient.scale.annotation.AutoRegister; +import lombok.NonNull; + +import java.io.IOException; +import java.io.InputStream; + +@AutoRegister(types = {Hash256.class, Hash.class, BlockHash.class}) +public class Hash256Reader implements ScaleReader { + @Override + public Hash256 read(@NonNull InputStream stream, ScaleReader... readers) throws IOException { + Preconditions.checkArgument(readers == null || readers.length == 0); + + return Hash256.fromBytes(Streamer.readBytes(Size.of32.getValue(), stream)); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java index 388ea089..d977b84f 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.rpc.api.section; -import com.strategyobject.substrateclient.crypto.PublicKey; +import com.strategyobject.substrateclient.common.types.Bytes; import com.strategyobject.substrateclient.rpc.annotation.RpcCall; import com.strategyobject.substrateclient.rpc.annotation.RpcInterface; import com.strategyobject.substrateclient.rpc.annotation.RpcSubscription; @@ -15,17 +15,45 @@ @RpcInterface("author") public interface Author { + + /** + * Checks if the keystore has private keys for the given public key and key type. + * + * @param publicKey public key + * @param keyType type of key + * @return `true` if a private key could be found + */ @RpcCall("hasKey") - CompletableFuture hasKey(@Scale PublicKey publicKey, String keyType); + CompletableFuture hasKey(Bytes publicKey, String keyType); + /** + * Insert a key into the keystore. + * + * @param keyType type of key + * @param secretUri secret uri + * @param publicKey public key + * @return void + */ @RpcCall("insertKey") - CompletableFuture insertKey(String keyType, String secretUri, @Scale PublicKey publicKey); - - @RpcCall("submitExtrinsic") - @Scale - CompletableFuture submitExtrinsic(@Scale Extrinsic extrinsic); + CompletableFuture insertKey(String keyType, String secretUri, Bytes publicKey); + /** + * Submit an extrinsic to watch. + * + * @param extrinsic extrinsic to submit + * @param callback callback handler + * @return unsubscribe delegate + */ @RpcSubscription(type = "extrinsicUpdate", subscribeMethod = "submitAndWatchExtrinsic", unsubscribeMethod = "unwatchExtrinsic") CompletableFuture>> submitAndWatchExtrinsic(@Scale Extrinsic extrinsic, BiConsumer callback); + + /** + * Submit hex-encoded extrinsic for inclusion in block. + * + * @param extrinsic extrinsic to submit + * @return hash of extrinsic + */ + @RpcCall("submitExtrinsic") + CompletableFuture submitExtrinsic(@Scale Extrinsic extrinsic); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Chain.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Chain.java index d68c597d..7b6564a2 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Chain.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Chain.java @@ -4,9 +4,9 @@ import com.strategyobject.substrateclient.rpc.annotation.RpcInterface; import com.strategyobject.substrateclient.rpc.annotation.RpcSubscription; import com.strategyobject.substrateclient.rpc.api.BlockHash; +import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.rpc.api.Header; import com.strategyobject.substrateclient.rpc.api.SignedBlock; -import com.strategyobject.substrateclient.scale.annotation.Scale; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; @@ -14,17 +14,55 @@ @RpcInterface("chain") public interface Chain { + + /** + * Get header and body of a relay chain block. + * + * @return current signed block + */ + @RpcCall("getBlock") + CompletableFuture getBlock(); + + /** + * Get header and body of a relay chain block. + * + * @param hash hash of the wanted block, or empty for the latest block + * @return signed block + */ + @RpcCall("getBlock") + CompletableFuture getBlock(BlockHash hash); + + /** + * Get hash of the n-th block in the canon chain. + * + * @return block hash + */ + @RpcCall("getBlockHash") + CompletableFuture getBlockHash(); + + /** + * Get hash of the n-th block in the canon chain. + * + * @param blockNumber number of wanted block + * @return block hash + */ + @RpcCall("getBlockHash") + CompletableFuture getBlockHash(BlockNumber blockNumber); + + /** + * Get hash of the last finalized block in the canon chain. + * + * @return hash of the last finalized block + */ @RpcCall("getFinalizedHead") - @Scale CompletableFuture getFinalizedHead(); + /** + * Retrieves the best header via subscription. + * + * @param callback callback handler + * @return unsubscribe delegate + */ @RpcSubscription(type = "newHead", subscribeMethod = "subscribeNewHead", unsubscribeMethod = "unsubscribeNewHead") CompletableFuture>> subscribeNewHeads(BiConsumer callback); - - @RpcCall("getBlockHash") - @Scale - CompletableFuture getBlockHash(long number); - - @RpcCall("getBlock") - CompletableFuture getBlock(@Scale BlockHash hash); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/State.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/State.java index c983e191..1df70a31 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/State.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/State.java @@ -13,65 +13,208 @@ @RpcInterface("state") public interface State { - @RpcCall("getRuntimeVersion") - CompletableFuture getRuntimeVersion(); - - @RpcCall("getMetadata") - @Scale - CompletableFuture getMetadata(); - + /** + * Returns the keys with prefix, leave empty to get all the keys. + * + * @param key prefix + * @return storage keys + */ @RpcCall("getKeys") CompletableFuture> getKeys(StorageKey key); - @RpcCall("getKeys") - CompletableFuture> getKeys(StorageKey key, @Scale BlockHash at); + /** + * Returns the keys with prefix, leave empty to get all the keys. + * + * @param key prefix + * @param at block hash + * @return storage keys + */ + @RpcCall("getKeys") + CompletableFuture> getKeys(StorageKey key, BlockHash at); + + /** + * Returns the keys with prefix with pagination support. + * + * @param key prefix + * @param count up to count keys will be returned + * @return storage keys + */ @RpcCall("getKeysPaged") CompletableFuture> getKeysPaged(StorageKey key, int count); + /** + * Returns the keys with prefix with pagination support. + * + * @param key prefix + * @param count up to count keys will be returned + * @param startKey if `start_key` is passed, return next keys in storage in lexicographic order + * @return storage keys + */ @RpcCall("getKeysPaged") CompletableFuture> getKeysPaged(StorageKey key, int count, StorageKey startKey); + /** + * Returns the keys with prefix with pagination support. + * + * @param key prefix + * @param count up to count keys will be returned + * @param startKey if `start_key` is passed, return next keys in storage in lexicographic order + * @param at block hash + * @return storage keys + */ @RpcCall("getKeysPaged") CompletableFuture> getKeysPaged(StorageKey key, int count, StorageKey startKey, - @Scale BlockHash at); + BlockHash at); + + /** + * Returns the runtime metadata as an opaque blob. + * + * @return runtime metadata + */ + @RpcCall("getMetadata") + @Scale + CompletableFuture getMetadata(); + + /** + * Returns the runtime metadata as an opaque blob. + * + * @param at block hash + * @return runtime metadata + */ + @RpcCall("getMetadata") + @Scale + CompletableFuture getMetadata(BlockHash at); + /** + * Get the runtime version. + * + * @return runtime version + */ + @RpcCall("getRuntimeVersion") + CompletableFuture getRuntimeVersion(); + + /** + * Get the runtime version. + * + * @param at block hash + * @return runtime version + */ + @RpcCall("getRuntimeVersion") + CompletableFuture getRuntimeVersion(BlockHash at); + + /** + * Returns a storage entry at a specific block's state. + * + * @param key storage key + * @return storage entry + */ @RpcCall("getStorage") CompletableFuture getStorage(StorageKey key); + /** + * Returns a storage entry at a specific block's state. + * + * @param key storage key + * @param at block hash + * @return storage entry + */ @RpcCall("getStorage") - CompletableFuture getStorage(StorageKey key, @Scale BlockHash at); - + CompletableFuture getStorage(StorageKey key, BlockHash at); + + /** + * Returns the hash of a storage entry at a block's state. + * + * @param key storage key + * @return hash of a storage entry + */ @RpcCall("getStorageHash") - @Scale CompletableFuture getStorageHash(StorageKey key); + /** + * Returns the hash of a storage entry at a block's state. + * + * @param key storage key + * @param at block hash + * @return hash of a storage entry + */ @RpcCall("getStorageHash") - @Scale - CompletableFuture getStorageHash(StorageKey key, @Scale BlockHash at); - + CompletableFuture getStorageHash(StorageKey key, BlockHash at); + + /** + * Returns the size of a storage entry at a block's state. + * + * @param key storage key + * @return size of a storage entry + */ @RpcCall("getStorageSize") CompletableFuture getStorageSize(StorageKey key); + /** + * Returns the size of a storage entry at a block's state. + * + * @param key storage key + * @param at block hash + * @return size of a storage entry + */ @RpcCall("getStorageSize") - CompletableFuture getStorageSize(StorageKey key, @Scale BlockHash at); - + CompletableFuture getStorageSize(StorageKey key, BlockHash at); + + /** + * Query historical storage entries (by key) starting from a block given as the second parameter. + * NOTE: This first returned result contains the initial state of storage for all keys. + * Subsequent values in the vector represent changes to the previous state (diffs). + * + * @param keys storage keys + * @param fromBlock hash of a starting block + * @return historical storage entries + */ @RpcCall("queryStorage") - CompletableFuture> queryStorage(List keys, @Scale BlockHash fromBlock); - + CompletableFuture> queryStorage(List keys, BlockHash fromBlock); + + /** + * Query historical storage entries (by key) starting from a block given as the second parameter. + * NOTE: This first returned result contains the initial state of storage for all keys. + * Subsequent values in the vector represent changes to the previous state (diffs). + * + * @param keys storage keys + * @param fromBlock hash of a starting block + * @param toBlock hash of an ending block + * @return historical storage entries + */ @RpcCall("queryStorage") CompletableFuture> queryStorage(List keys, - @Scale BlockHash fromBlock, - @Scale BlockHash toBlock); - + BlockHash fromBlock, + BlockHash toBlock); + + /** + * Query storage entries (by key) starting at block hash given as the second parameter. + * + * @param keys storage keys + * @return storage entries + */ @RpcCall("queryStorageAt") CompletableFuture> queryStorageAt(List keys); + /** + * Query storage entries (by key) starting at block hash given as the second parameter. + * + * @param keys storage keys + * @param at block hash + * @return storage entries + */ @RpcCall("queryStorageAt") - CompletableFuture> queryStorageAt(List keys, @Scale BlockHash at); - + CompletableFuture> queryStorageAt(List keys, BlockHash at); + + /** + * Subscribes to storage changes for the provided keys. + * + * @param keys storage keys + * @param callback callback handler + * @return unsubscribe delegate + */ @RpcSubscription(type = "storage", subscribeMethod = "subscribeStorage", unsubscribeMethod = "unsubscribeStorage") CompletableFuture>> subscribeStorage(List keys, BiConsumer callback); diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/System.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/System.java index f5326d2e..9c929397 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/System.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/System.java @@ -3,11 +3,21 @@ import com.strategyobject.substrateclient.rpc.annotation.RpcCall; import com.strategyobject.substrateclient.rpc.annotation.RpcInterface; import com.strategyobject.substrateclient.rpc.api.AccountId; +import com.strategyobject.substrateclient.rpc.api.Index; import java.util.concurrent.CompletableFuture; @RpcInterface("system") public interface System { + /** + * Returns the next valid index (aka nonce) for given account. + * This method takes into consideration all pending transactions + * currently in the pool and if no transactions are found in the pool + * it fallbacks to query the index from the runtime (aka. state nonce). + * + * @param accountId account + * @return the next account index available on the node + */ @RpcCall("accountNextIndex") - CompletableFuture accountNextIndex(AccountId accountId); + CompletableFuture accountNextIndex(AccountId accountId); } diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java index af84709f..3b5c3f0c 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java @@ -73,7 +73,7 @@ void insertKey() throws Exception { void submitExtrinsic() throws Exception { try (val wsProvider = connect()) { val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); - val genesis = chain.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val genesis = chain.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); val author = RpcGeneratedSectionFactory.create(Author.class, wsProvider); Assertions.assertDoesNotThrow(() -> author.submitExtrinsic(createBalanceTransferExtrinsic(genesis, NONCE.getAndIncrement())) @@ -85,7 +85,7 @@ void submitExtrinsic() throws Exception { void submitAndWatchExtrinsic() throws Exception { try (val wsProvider = connect()) { val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); - val genesis = chain.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val genesis = chain.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); val author = RpcGeneratedSectionFactory.create(Author.class, wsProvider); val updateCount = new AtomicInteger(0); @@ -128,7 +128,7 @@ private WsProvider connect() throws ExecutionException, InterruptedException, Ti val tip = 0; val call = new BalanceTransfer(moduleIndex, callIndex, AddressId.fromBytes(bobKeyPair().asPublicKey().getData()), BigInteger.valueOf(10)); - val extra = new SignedExtra<>(specVersion, txVersion, genesis, genesis, new ImmortalEra(), BigInteger.valueOf(nonce), BigInteger.valueOf(tip)); + val extra = new SignedExtra<>(specVersion, txVersion, genesis, genesis, new ImmortalEra(), Index.of(nonce), BigInteger.valueOf(tip)); val signedPayload = new SignedPayload<>(call, extra); val keyRing = KeyRing.fromKeyPair(aliceKeyPair()); diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java index aefebf69..a36acfcb 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java @@ -2,7 +2,7 @@ import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; import com.strategyobject.substrateclient.rpc.api.BlockHash; -import com.strategyobject.substrateclient.rpc.api.section.Chain; +import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -22,7 +22,7 @@ import static org.awaitility.Awaitility.await; import static org.hamcrest.Matchers.greaterThan; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.*; @Testcontainers class ChainTests { @@ -75,7 +75,7 @@ void subscribeNewHeads() throws Exception { void getBlockHash() throws Exception { try (val wsProvider = connect()) { val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); - val result = chain.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val result = chain.getBlockHash().get(WAIT_TIMEOUT, TimeUnit.SECONDS); assertNotEquals(BigInteger.ZERO, new BigInteger(result.getData())); } @@ -98,14 +98,37 @@ void getBlock() throws Exception { .untilAtomic(height, greaterThan(1)); val number = height.get(); - val blockHash = chain.getBlockHash(number).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val blockHash = chain.getBlockHash(BlockNumber.of(number)).get(WAIT_TIMEOUT, TimeUnit.SECONDS); assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.getData())); val block = chain.getBlock(blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBlock().getHeader().getParentHash().getData())); - Assertions.assertEquals(number, block.getBlock().getHeader().getNumber().getValue().intValue()); + assertEquals(number, block.getBlock().getHeader().getNumber().getValue().intValue()); + } + } + + @Test + void getCurrentBlock() throws ExecutionException, InterruptedException, TimeoutException { + try (val wsProvider = connect()) { + val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + + val height = new AtomicInteger(0); + chain.subscribeNewHeads((e, header) -> { + if (header != null) { + height.set(header.getNumber().getValue().intValue()); + } + }); + + await() + .atMost(WAIT_TIMEOUT * 3, TimeUnit.SECONDS) + .untilAtomic(height, greaterThan(2)); + + val block = chain.getBlock().get(WAIT_TIMEOUT, TimeUnit.SECONDS); + + assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBlock().getHeader().getParentHash().getData())); + assertNotNull(block.getBlock().getHeader().getNumber()); } } diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java index 5694e1e6..3bcad266 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java @@ -2,6 +2,7 @@ import com.strategyobject.substrateclient.common.utils.HexConverter; import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.rpc.api.StorageKey; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; @@ -97,7 +98,7 @@ void getStorageHandlesNullResponse() throws Exception { void getStorageAtBlock() throws Exception { try (val wsProvider = connect()) { val chainSection = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); - val blockHash = chainSection.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val blockHash = chainSection.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); val storageData = state.getStorage(storageKey, blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -123,7 +124,7 @@ void getStorageHash() throws Exception { void getStorageHashAt() throws Exception { try (val wsProvider = connect()) { val chainSection = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); - val blockHash = chainSection.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val blockHash = chainSection.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); val hash = state.getStorageHash(storageKey, blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -148,7 +149,7 @@ void getStorageSize() throws Exception { void getStorageSizeAt() throws Exception { try (val wsProvider = connect()) { val chainSection = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); - val blockHash = chainSection.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val blockHash = chainSection.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); val size = state.getStorageSize(storageKey, blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java index f000b7d6..1479871b 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java @@ -3,7 +3,7 @@ import com.strategyobject.substrateclient.common.utils.HexConverter; import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; import com.strategyobject.substrateclient.rpc.api.AccountId; -import com.strategyobject.substrateclient.rpc.api.section.System; +import com.strategyobject.substrateclient.rpc.api.Index; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -38,7 +38,7 @@ void accountNextIndex() throws Exception { val result = system.accountNextIndex(AccountId.fromBytes(alicePublicKey)) .get(WAIT_TIMEOUT, TimeUnit.SECONDS); - Assertions.assertEquals(0, result); + Assertions.assertEquals(Index.ZERO, result); } } } diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java index b92d66bb..6b0a4d31 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java @@ -116,7 +116,7 @@ private void addMethodBody(MethodSpec.Builder methodSpec, for (Element element : classElement.getEnclosedElements()) { if (element instanceof VariableElement) { val field = (VariableElement) element; - if (field.getAnnotation(Ignore.class) == null) { + if (field.getAnnotation(Ignore.class) == null && !field.getModifiers().contains(Modifier.STATIC)) { setField(methodSpec, field, context.getTypeUtils(), scaleAnnotationParser, compositor); } } diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java index b84c5058..7481e891 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java @@ -116,7 +116,7 @@ private void addMethodBody(MethodSpec.Builder methodSpec, for (Element element : classElement.getEnclosedElements()) { if (element instanceof VariableElement) { val field = (VariableElement) element; - if (field.getAnnotation(Ignore.class) == null) { + if (field.getAnnotation(Ignore.class) == null && !field.getModifiers().contains(Modifier.STATIC)) { setField(methodSpec, field, scaleAnnotationParser, compositor); } }