From 519c1eeb40095444cd990f0f1c2c89b46bb786f6 Mon Sep 17 00:00:00 2001 From: Vadim Nabiev Date: Thu, 27 Jan 2022 22:42:25 +0300 Subject: [PATCH] method `chain.getBlock(hash)` and corresponding classes are added --- .../substrateclient/rpc/sections/Chain.java | 4 ++ .../rpc/sections/ChainTests.java | 51 +++++++++++++++---- .../substrateclient/rpc/types/Block.java | 16 ++++++ .../substrateclient/rpc/types/Header.java | 5 +- .../substrateclient/rpc/types/Number.java | 12 +++++ .../rpc/types/NumberDecoder.java | 19 +++++++ .../rpc/types/SignedBlock.java | 12 +++++ 7 files changed, 109 insertions(+), 10 deletions(-) create mode 100644 rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Block.java create mode 100644 rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Number.java create mode 100644 rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/NumberDecoder.java create mode 100644 rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/SignedBlock.java diff --git a/rpc/rpc-sections/src/main/java/com/strategyobject/substrateclient/rpc/sections/Chain.java b/rpc/rpc-sections/src/main/java/com/strategyobject/substrateclient/rpc/sections/Chain.java index 0f530712..e4056317 100644 --- a/rpc/rpc-sections/src/main/java/com/strategyobject/substrateclient/rpc/sections/Chain.java +++ b/rpc/rpc-sections/src/main/java/com/strategyobject/substrateclient/rpc/sections/Chain.java @@ -5,6 +5,7 @@ import com.strategyobject.substrateclient.rpc.core.annotations.RpcSubscription; import com.strategyobject.substrateclient.rpc.types.BlockHash; import com.strategyobject.substrateclient.rpc.types.Header; +import com.strategyobject.substrateclient.rpc.types.SignedBlock; import com.strategyobject.substrateclient.scale.annotations.Scale; import java.util.concurrent.CompletableFuture; @@ -23,4 +24,7 @@ public interface Chain { @RpcCall(method = "getBlockHash") @Scale CompletableFuture getBlockHash(long number); + + @RpcCall(method = "getBlock") + CompletableFuture getBlock(@Scale BlockHash hash); } diff --git a/rpc/rpc-sections/src/test/java/com/strategyobject/substrateclient/rpc/sections/ChainTests.java b/rpc/rpc-sections/src/test/java/com/strategyobject/substrateclient/rpc/sections/ChainTests.java index f3fd0897..687dd34a 100644 --- a/rpc/rpc-sections/src/test/java/com/strategyobject/substrateclient/rpc/sections/ChainTests.java +++ b/rpc/rpc-sections/src/test/java/com/strategyobject/substrateclient/rpc/sections/ChainTests.java @@ -21,8 +21,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.assertTrue; +import static org.junit.jupiter.api.Assertions.*; @Testcontainers public class ChainTests { @@ -42,11 +41,11 @@ void getFinalizedHead() throws ExecutionException, InterruptedException, Timeout wsProvider.connect().get(WAIT_TIMEOUT, TimeUnit.SECONDS); val sectionFactory = new RpcGeneratedSectionFactory(); - Chain rpcSection = sectionFactory.create(Chain.class, wsProvider); + val rpcSection = sectionFactory.create(Chain.class, wsProvider); - BlockHash result = rpcSection.getFinalizedHead().get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val result = rpcSection.getFinalizedHead().get(WAIT_TIMEOUT, TimeUnit.SECONDS); - assertNotEquals(new BigInteger(result.getData()), BigInteger.ZERO); + assertNotEquals(BigInteger.ZERO, new BigInteger(result.getData())); } } @@ -59,7 +58,7 @@ void subscribeNewHeads() throws ExecutionException, InterruptedException, Timeou wsProvider.connect().get(WAIT_TIMEOUT, TimeUnit.SECONDS); val sectionFactory = new RpcGeneratedSectionFactory(); - Chain rpcSection = sectionFactory.create(Chain.class, wsProvider); + val rpcSection = sectionFactory.create(Chain.class, wsProvider); val blockCount = new AtomicInteger(0); val blockHash = new AtomicReference(null); @@ -76,7 +75,7 @@ void subscribeNewHeads() throws ExecutionException, InterruptedException, Timeou .atMost(WAIT_TIMEOUT * 2, TimeUnit.SECONDS) .untilAtomic(blockCount, greaterThan(2)); - assertNotEquals(new BigInteger(blockHash.get().getData()), BigInteger.ZERO); + assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.get().getData())); val result = unsubscribeFunc.get().get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -86,6 +85,23 @@ void subscribeNewHeads() throws ExecutionException, InterruptedException, Timeou @Test void getBlockHash() throws ExecutionException, InterruptedException, TimeoutException, RpcInterfaceInitializationException { + try (WsProvider wsProvider = WsProvider.builder() + .setEndpoint(substrate.getWsAddress()) + .disableAutoConnect() + .build()) { + wsProvider.connect().get(WAIT_TIMEOUT, TimeUnit.SECONDS); + + val sectionFactory = new RpcGeneratedSectionFactory(); + val rpcSection = sectionFactory.create(Chain.class, wsProvider); + + val result = rpcSection.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + + assertNotEquals(BigInteger.ZERO, new BigInteger(result.getData())); + } + } + + @Test + void getBlock() throws ExecutionException, InterruptedException, TimeoutException, RpcInterfaceInitializationException { try (WsProvider wsProvider = WsProvider.builder() .setEndpoint(substrate.getWsAddress()) .disableAutoConnect() @@ -95,9 +111,26 @@ void getBlockHash() throws ExecutionException, InterruptedException, TimeoutExce val sectionFactory = new RpcGeneratedSectionFactory(); Chain rpcSection = sectionFactory.create(Chain.class, wsProvider); - BlockHash result = rpcSection.getBlockHash(0).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + val height = new AtomicInteger(0); + rpcSection.subscribeNewHeads((e, header) -> { + if (header != null) { + height.set(header.getNumber().getValue().intValue()); + } + }); + + await() + .atMost(WAIT_TIMEOUT * 3, TimeUnit.SECONDS) + .untilAtomic(height, greaterThan(1)); + + val number = height.get(); + val blockHash = rpcSection.getBlockHash(number).get(WAIT_TIMEOUT, TimeUnit.SECONDS); + + assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.getData())); + + val block = rpcSection.getBlock(blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - assertNotEquals(new BigInteger(result.getData()), BigInteger.ZERO); + assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBlock().getHeader().getParentHash().getData())); + assertEquals(number, block.getBlock().getHeader().getNumber().getValue().intValue()); } } } diff --git a/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Block.java b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Block.java new file mode 100644 index 00000000..65171ccc --- /dev/null +++ b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Block.java @@ -0,0 +1,16 @@ +package com.strategyobject.substrateclient.rpc.types; + +import com.strategyobject.substrateclient.rpc.core.annotations.RpcDecoder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@RpcDecoder +@Getter +@Setter +public class Block { + private Header header; + + private List extrinsics; // TODO think about a more strict type +} diff --git a/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Header.java b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Header.java index bdb99163..8eded354 100644 --- a/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Header.java +++ b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Header.java @@ -8,7 +8,10 @@ @Getter @Setter @RpcDecoder -public class Header { +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 */ } diff --git a/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Number.java b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Number.java new file mode 100644 index 00000000..d66a76ee --- /dev/null +++ b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/Number.java @@ -0,0 +1,12 @@ +package com.strategyobject.substrateclient.rpc.types; + +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-types/src/main/java/com/strategyobject/substrateclient/rpc/types/NumberDecoder.java b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/NumberDecoder.java new file mode 100644 index 00000000..6cc5a833 --- /dev/null +++ b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/NumberDecoder.java @@ -0,0 +1,19 @@ +package com.strategyobject.substrateclient.rpc.types; + +import com.strategyobject.substrateclient.rpc.core.DecoderPair; +import com.strategyobject.substrateclient.rpc.core.annotations.AutoRegister; +import com.strategyobject.substrateclient.rpc.core.decoders.AbstractDecoder; +import lombok.val; + +import java.math.BigInteger; + +@AutoRegister(types = Number.class) +public class NumberDecoder extends AbstractDecoder { + @Override + protected Number decodeNonNull(Object value, DecoderPair[] decoders) { + val stringValue = (String) value; + val number = new BigInteger(stringValue.substring(2), 16); + + return Number.of(number); + } +} diff --git a/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/SignedBlock.java b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/SignedBlock.java new file mode 100644 index 00000000..9bb676ca --- /dev/null +++ b/rpc/rpc-types/src/main/java/com/strategyobject/substrateclient/rpc/types/SignedBlock.java @@ -0,0 +1,12 @@ +package com.strategyobject.substrateclient.rpc.types; + +import com.strategyobject.substrateclient.rpc.core.annotations.RpcDecoder; +import lombok.Getter; +import lombok.Setter; + +@RpcDecoder +@Getter +@Setter +public class SignedBlock { // TODO add rest fields + private Block block; +}