From 9ba300530b1e6fcc681b6df24ec6eefbe767d656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9Cur=D0=B0d=20H=D0=B0mz=D0=B0?= Date: Thu, 6 Jun 2024 13:26:18 +0300 Subject: [PATCH] feat: improve syncing startegies (#447) # Description - What does this PR do? 'Get rid' of the old SyncedState class. Create a new class (SyncState) that holds only relevant information about the current sync state and keeps it in the database. Automatically switch to full sync after warp sync. (Currently starts from the first block, but after trie version 1 implementation will update it to start from the latest warp sync block). Fixes #335 ## Checklist: - [x] I have read the [contributing guidelines](../CONTRIBUTING.md). - [x] My PR title matches the [Conventional Commits spec](https://www.conventionalcommits.org/). - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [x] All new and existing tests passed. --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/dependabot.yml | 1 + README.md | 8 +- build.gradle.kts | 4 +- docs/overview.md | 2 +- .../chain/lightsyncstate/Authority.java | 6 +- .../lightsyncstate/scale/AuthorityReader.java | 3 +- .../java/com/limechain/client/FullNode.java | 10 +- .../java/com/limechain/config/SystemInfo.java | 9 +- .../limechain/network/ConnectionManager.java | 4 +- .../java/com/limechain/network/Network.java | 12 +- .../blockannounce/BlockAnnounceEngine.java | 26 +- .../BlockAnnounceHandshake.java | 2 +- .../BlockAnnounceHandshakeBuilder.java | 39 +++ .../BlockAnnounceMessage.java | 2 +- .../BlockAnnounceHandshakeScaleReader.java | 1 + .../BlockAnnounceHandshakeScaleWriter.java | 1 + .../BlockAnnounceMessageScaleReader.java | 1 + .../protocol/grandpa/GrandpaEngine.java | 35 ++- .../neighbour/NeighbourMessageBuilder.java | 20 ++ .../network/protocol/sync/SyncMessages.java | 2 +- .../transactions/TransactionsEngine.java | 9 +- .../rpc/client/AbstractRpcClient.java | 2 +- .../limechain/rpc/config/CommonConfig.java | 33 ++- .../rpc/methods/system/SystemRPCImpl.java | 10 +- .../com/limechain/rpc/server/AppBean.java | 4 + .../com/limechain/runtime/RuntimeBuilder.java | 35 --- .../hostapi/OffchainHostFunctions.java | 12 +- .../com/limechain/storage/DBConstants.java | 20 +- .../com/limechain/storage/DBRepository.java | 29 +-- .../limechain/storage/block/SyncState.java | 92 +++++++ .../limechain/sync/JustificationVerifier.java | 40 +-- .../sync/fullsync/FullSyncMachine.java | 9 +- .../sync/warpsync/WarpSyncMachine.java | 92 +++---- .../{SyncedState.java => WarpSyncState.java} | 237 +++++++----------- .../ChainInformationBuildAction.java} | 30 ++- .../ChainInformationDownloadAction.java} | 6 +- .../FinishedAction.java} | 14 +- .../RequestFragmentsAction.java} | 22 +- .../warpsync/action/RuntimeBuildAction.java | 35 +++ .../RuntimeDownloadAction.java} | 26 +- .../VerifyJustificationAction.java} | 42 ++-- .../WarpSyncAction.java} | 4 +- .../limechain/sync/warpsync/dto/StateDto.java | 12 - .../warpsync/state/RuntimeBuildState.java | 33 --- .../com/limechain/config/SystemInfoTest.java | 10 +- .../network/ConnectionManagerTest.java | 2 +- .../BlockAnnounceControllerTest.java | 6 + .../BlockAnnounceEngineTest.java | 19 +- .../BlockAnnounceProtocolTest.java | 33 ++- .../BlockAnnounceServiceTest.java | 2 +- ...BlockAnnounceHandshakeScaleReaderTest.java | 1 + .../protocol/grandpa/GrandpaEngineTest.java | 42 ++-- .../rpc/methods/system/SystemRPCImplTest.java | 10 +- ...StateTest.java => WarpSyncActionTest.java} | 102 ++++---- .../RuntimeBuildStateTest.java | 12 +- .../RuntimeDownloadStateTest.java | 33 +-- .../RuntimeDownloadTest.java | 4 +- 58 files changed, 724 insertions(+), 590 deletions(-) rename src/main/java/com/limechain/network/protocol/blockannounce/{scale => messages}/BlockAnnounceHandshake.java (85%) create mode 100644 src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceHandshakeBuilder.java rename src/main/java/com/limechain/network/protocol/blockannounce/{scale => messages}/BlockAnnounceMessage.java (86%) create mode 100644 src/main/java/com/limechain/network/protocol/grandpa/messages/neighbour/NeighbourMessageBuilder.java create mode 100644 src/main/java/com/limechain/storage/block/SyncState.java rename src/main/java/com/limechain/sync/warpsync/{SyncedState.java => WarpSyncState.java} (64%) rename src/main/java/com/limechain/sync/warpsync/{state/ChainInformationBuildState.java => action/ChainInformationBuildAction.java} (53%) rename src/main/java/com/limechain/sync/warpsync/{state/ChainInformationDownloadState.java => action/ChainInformationDownloadAction.java} (91%) rename src/main/java/com/limechain/sync/warpsync/{state/FinishedState.java => action/FinishedAction.java} (59%) rename src/main/java/com/limechain/sync/warpsync/{state/RequestFragmentsState.java => action/RequestFragmentsAction.java} (78%) create mode 100644 src/main/java/com/limechain/sync/warpsync/action/RuntimeBuildAction.java rename src/main/java/com/limechain/sync/warpsync/{state/RuntimeDownloadState.java => action/RuntimeDownloadAction.java} (58%) rename src/main/java/com/limechain/sync/warpsync/{state/VerifyJustificationState.java => action/VerifyJustificationAction.java} (61%) rename src/main/java/com/limechain/sync/warpsync/{state/WarpSyncState.java => action/WarpSyncAction.java} (63%) delete mode 100644 src/main/java/com/limechain/sync/warpsync/dto/StateDto.java delete mode 100644 src/main/java/com/limechain/sync/warpsync/state/RuntimeBuildState.java rename src/test/java/com/limechain/sync/warpsync/{SyncedStateTest.java => WarpSyncActionTest.java} (63%) rename src/test/java/com/limechain/sync/warpsync/{state => action}/RuntimeBuildStateTest.java (69%) rename src/test/java/com/limechain/sync/warpsync/{state => action}/RuntimeDownloadStateTest.java (69%) rename src/test/java/com/limechain/sync/warpsync/{state => action}/RuntimeDownloadTest.java (99%) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 805e0dcac..ae492eb0a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,7 +12,7 @@ including:* Fixes # ## Checklist: -- [ ] I have read the [contributing guidelines](../CONTRIBUTING.md). +- [ ] I have read the [contributing guidelines](https://github.com/LimeChain/Fruzhin/blob/dev/CONTRIBUTING.md). - [ ] My PR title matches the [Conventional Commits spec](https://www.conventionalcommits.org/). - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e07581508..20b222195 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,4 @@ updates: directory: "/" schedule: interval: "weekly" + open-pull-requests-limit: 10 \ No newline at end of file diff --git a/README.md b/README.md index d5498ff48..271f7379c 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,7 @@ cd Fruzhin ### Java Version -Fruzhin only works -with [Java 21 Coretto](https://docs.aws.amazon.com/corretto/latest/corretto-21-ug/downloads-list.html). Using any other -version may cause "cannot calculate secret" errors when running the node: - -``` -org.bouncycastle.tls.crypto.TlsCryptoException: cannot calculate secret -``` +Fruzhin only works with Java 21. If you have multiple java version installed please make sure you're using 21: diff --git a/build.gradle.kts b/build.gradle.kts index 9b1d3133d..3f1dbe399 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java") id("io.freefair.lombok") version "8.6" - id("org.springframework.boot") version "3.2.5" + id("org.springframework.boot") version "3.2.6" id("io.spring.dependency-management") version "1.1.5" id("application") } @@ -63,7 +63,7 @@ dependencies { // Nabu // implementation("com.github.LimeChain:nabu:master-SNAPSHOT") // Uncomment for "most-recent on the master branch" - implementation("com.github.LimeChain:nabu:32f159f413") + implementation("com.github.LimeChain:nabu:0.7.8") //JSON-RPC implementation("com.github.LimeChain:jsonrpc4j:1.7.0") diff --git a/docs/overview.md b/docs/overview.md index 6e8168a7e..8a7ef3209 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -19,7 +19,7 @@ git clone https://github.com/LimeChain/Fruzhin.git cd Fruzhin ``` -#### Install java 21 corretto (if you don't already have it) +#### Install java 21 (if you don't already have it) Setup guide: - [Windows](https://docs.aws.amazon.com/corretto/latest/corretto-21-ug/windows-install.html) - [Linux](https://docs.aws.amazon.com/corretto/latest/corretto-21-ug/generic-linux-install.html) diff --git a/src/main/java/com/limechain/chain/lightsyncstate/Authority.java b/src/main/java/com/limechain/chain/lightsyncstate/Authority.java index 07e9ac437..e612d2efd 100644 --- a/src/main/java/com/limechain/chain/lightsyncstate/Authority.java +++ b/src/main/java/com/limechain/chain/lightsyncstate/Authority.java @@ -1,14 +1,14 @@ package com.limechain.chain.lightsyncstate; -import io.emeraldpay.polkaj.types.Hash256; import lombok.AllArgsConstructor; import lombok.Getter; +import java.io.Serializable; import java.math.BigInteger; @Getter @AllArgsConstructor -public class Authority { - private final Hash256 publicKey; +public class Authority implements Serializable { + private final byte[] publicKey; private final BigInteger weight; } diff --git a/src/main/java/com/limechain/chain/lightsyncstate/scale/AuthorityReader.java b/src/main/java/com/limechain/chain/lightsyncstate/scale/AuthorityReader.java index aaa534156..16b9d96f1 100644 --- a/src/main/java/com/limechain/chain/lightsyncstate/scale/AuthorityReader.java +++ b/src/main/java/com/limechain/chain/lightsyncstate/scale/AuthorityReader.java @@ -4,11 +4,10 @@ import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleReader; import io.emeraldpay.polkaj.scale.reader.UInt64Reader; -import io.emeraldpay.polkaj.types.Hash256; public class AuthorityReader implements ScaleReader { @Override public Authority read(ScaleCodecReader reader) { - return new Authority(new Hash256(reader.readUint256()), new UInt64Reader().read(reader)); + return new Authority(reader.readUint256(), new UInt64Reader().read(reader)); } } diff --git a/src/main/java/com/limechain/client/FullNode.java b/src/main/java/com/limechain/client/FullNode.java index 0f42a1c30..f2a4c6a84 100644 --- a/src/main/java/com/limechain/client/FullNode.java +++ b/src/main/java/com/limechain/client/FullNode.java @@ -56,9 +56,15 @@ public void start() { log.log(Level.INFO, "Node successfully connected to a peer! Sync can start!"); CliArguments args = AppBean.getBean(CliArguments.class); + WarpSyncMachine warpSyncMachine = AppBean.getBean(WarpSyncMachine.class); + FullSyncMachine fullSyncMachine = AppBean.getBean(FullSyncMachine.class); + switch (args.syncMode()) { - case FULL -> AppBean.getBean(FullSyncMachine.class).start(); - case WARP -> AppBean.getBean(WarpSyncMachine.class).start(); + case FULL -> fullSyncMachine.start(); + case WARP -> { + warpSyncMachine.onFinish(() -> fullSyncMachine.start()); + warpSyncMachine.start(); + } default -> throw new IllegalStateException("Unexpected value: " + args.syncMode()); } } diff --git a/src/main/java/com/limechain/config/SystemInfo.java b/src/main/java/com/limechain/config/SystemInfo.java index 3174bc89d..c55b3d7f2 100644 --- a/src/main/java/com/limechain/config/SystemInfo.java +++ b/src/main/java/com/limechain/config/SystemInfo.java @@ -2,11 +2,12 @@ import com.limechain.chain.Chain; import com.limechain.network.Network; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.storage.block.SyncState; import lombok.Getter; import lombok.extern.java.Log; import org.springframework.beans.factory.annotation.Value; +import java.math.BigInteger; import java.nio.file.FileSystems; import java.util.logging.Level; @@ -24,12 +25,14 @@ public class SystemInfo { private String hostName; @Value("${host.version}") private String hostVersion; + private final BigInteger highestBlock; - public SystemInfo(HostConfig hostConfig, Network network) { + public SystemInfo(HostConfig hostConfig, Network network, SyncState syncState) { this.role = network.getNodeRole().name(); this.chain = hostConfig.getChain(); this.dbPath = hostConfig.getRocksDbPath(); this.hostIdentity = network.getHost().getPeerId().toString(); + this.highestBlock = syncState.getLastFinalizedBlockNumber(); } /** @@ -53,6 +56,6 @@ public void logSystemInfo() { log.log(Level.INFO, "Local node identity is: " + hostIdentity); log.log(Level.INFO, "Operating System: " + System.getProperty("os.name")); log.log(Level.INFO, "CPU architecture: " + System.getProperty("os.arch")); - log.log(Level.INFO, "Highest known block at #" + SyncedState.getInstance().getLastFinalizedBlockNumber()); + log.log(Level.INFO, "Highest known block at #" + highestBlock); } } diff --git a/src/main/java/com/limechain/network/ConnectionManager.java b/src/main/java/com/limechain/network/ConnectionManager.java index d2e35f735..f64cc7f70 100644 --- a/src/main/java/com/limechain/network/ConnectionManager.java +++ b/src/main/java/com/limechain/network/ConnectionManager.java @@ -3,8 +3,8 @@ import com.limechain.network.dto.PeerInfo; import com.limechain.network.dto.ProtocolStreamType; import com.limechain.network.dto.ProtocolStreams; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshake; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessage; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceMessage; import com.limechain.network.protocol.warp.dto.BlockHeader; import io.libp2p.core.PeerId; import io.libp2p.core.Stream; diff --git a/src/main/java/com/limechain/network/Network.java b/src/main/java/com/limechain/network/Network.java index b5bb51d6b..6e3f02d01 100644 --- a/src/main/java/com/limechain/network/Network.java +++ b/src/main/java/com/limechain/network/Network.java @@ -19,9 +19,10 @@ import com.limechain.network.protocol.transactions.TransactionsService; import com.limechain.network.protocol.warp.WarpSyncService; import com.limechain.network.protocol.warp.dto.WarpSyncResponse; +import com.limechain.rpc.server.AppBean; import com.limechain.storage.DBConstants; import com.limechain.storage.KVRepository; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.sync.warpsync.WarpSyncState; import com.limechain.utils.Ed25519Utils; import com.limechain.utils.StringUtils; import io.ipfs.multiaddr.MultiAddress; @@ -58,13 +59,11 @@ public class Network { private static final int HOST_PORT = 30333; private static final Random RANDOM = new Random(); @Getter - private static Network network; - @Getter private final Chain chain; @Getter private final NodeRole nodeRole; private final String[] bootNodes; - private final ConnectionManager connectionManager = ConnectionManager.getInstance(); + private final ConnectionManager connectionManager; private SyncService syncService; private StateService stateService; private LightMessagesService lightMessagesService; @@ -99,6 +98,7 @@ public Network(ChainService chainService, HostConfig hostConfig, KVRepository grandpaService.sendNeighbourMessage(this.host, peerId)); diff --git a/src/main/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngine.java b/src/main/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngine.java index 4f74d6235..6311cf219 100644 --- a/src/main/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngine.java +++ b/src/main/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngine.java @@ -3,19 +3,23 @@ import com.limechain.exception.scale.ScaleEncodingException; import com.limechain.exception.storage.BlockNodeNotFoundException; import com.limechain.network.ConnectionManager; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshakeBuilder; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceMessage; import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshakeScaleReader; import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshakeScaleWriter; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessage; import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessageScaleReader; import com.limechain.network.protocol.warp.dto.Block; import com.limechain.network.protocol.warp.dto.BlockBody; +import com.limechain.rpc.server.AppBean; import com.limechain.storage.block.BlockState; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.sync.warpsync.WarpSyncState; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleCodecWriter; import io.libp2p.core.PeerId; import io.libp2p.core.Stream; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.extern.java.Log; import java.io.ByteArrayOutputStream; @@ -24,10 +28,18 @@ import java.util.logging.Level; @Log +@AllArgsConstructor(access = AccessLevel.PROTECTED) public class BlockAnnounceEngine { public static final int HANDSHAKE_LENGTH = 69; - protected ConnectionManager connectionManager = ConnectionManager.getInstance(); - protected SyncedState syncedState = SyncedState.getInstance(); + protected ConnectionManager connectionManager; + protected WarpSyncState warpSyncState; + protected BlockAnnounceHandshakeBuilder handshakeBuilder; + + public BlockAnnounceEngine() { + connectionManager = ConnectionManager.getInstance(); + warpSyncState = AppBean.getBean(WarpSyncState.class); + handshakeBuilder = new BlockAnnounceHandshakeBuilder(); + } public void receiveRequest(byte[] msg, Stream stream) { PeerId peerId = stream.remotePeerId(); @@ -71,7 +83,7 @@ private void handleBlockAnnounce(byte[] msg, PeerId peerId) { ScaleCodecReader reader = new ScaleCodecReader(msg); BlockAnnounceMessage announce = reader.read(new BlockAnnounceMessageScaleReader()); connectionManager.updatePeer(peerId, announce); - syncedState.syncBlockAnnounce(announce); + warpSyncState.syncBlockAnnounce(announce); log.log(Level.FINE, "Received block announce for block #" + announce.getHeader().getBlockNumber() + " from " + peerId + " with hash:0x" + announce.getHeader().getHash() + @@ -92,7 +104,7 @@ private void handleBlockAnnounce(byte[] msg, PeerId peerId) { public void writeHandshakeToStream(Stream stream, PeerId peerId) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); try (ScaleCodecWriter writer = new ScaleCodecWriter(buf)) { - writer.write(new BlockAnnounceHandshakeScaleWriter(), syncedState.getHandshake()); + writer.write(new BlockAnnounceHandshakeScaleWriter(), handshakeBuilder.getBlockAnnounceHandshake()); } catch (IOException e) { throw new ScaleEncodingException(e); } diff --git a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshake.java b/src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceHandshake.java similarity index 85% rename from src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshake.java rename to src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceHandshake.java index 408db2569..b89f0ee08 100644 --- a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshake.java +++ b/src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceHandshake.java @@ -1,4 +1,4 @@ -package com.limechain.network.protocol.blockannounce.scale; +package com.limechain.network.protocol.blockannounce.messages; import io.emeraldpay.polkaj.types.Hash256; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceHandshakeBuilder.java b/src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceHandshakeBuilder.java new file mode 100644 index 000000000..9b14e11ad --- /dev/null +++ b/src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceHandshakeBuilder.java @@ -0,0 +1,39 @@ +package com.limechain.network.protocol.blockannounce.messages; + +import com.limechain.config.HostConfig; +import com.limechain.network.protocol.blockannounce.NodeRole; +import com.limechain.rpc.server.AppBean; +import com.limechain.storage.block.SyncState; +import io.emeraldpay.polkaj.types.Hash256; + +import java.math.BigInteger; + +public class BlockAnnounceHandshakeBuilder { + + /** + * Creates a Block Announce handshake based on the latest finalized Host state + * + * @return our Block Announce handshake + */ + public BlockAnnounceHandshake getBlockAnnounceHandshake() { + SyncState syncState = AppBean.getBean(SyncState.class); + HostConfig hostConfig = AppBean.getBean(HostConfig.class); + + Hash256 genesisBlockHash = syncState.getGenesisBlockHash(); + Hash256 lastFinalizedBlockHash = syncState.getLastFinalizedBlockHash(); + BigInteger lastFinalizedBlockNumber = syncState.getLastFinalizedBlockNumber(); + + NodeRole nodeRole = hostConfig.getNodeRole(); + + Hash256 blockHash = lastFinalizedBlockHash == null + ? genesisBlockHash + : lastFinalizedBlockHash; + return new BlockAnnounceHandshake( + nodeRole.getValue(), + lastFinalizedBlockNumber, + blockHash, + genesisBlockHash + ); + } + +} diff --git a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceMessage.java b/src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceMessage.java similarity index 86% rename from src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceMessage.java rename to src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceMessage.java index e2efe0636..4ff7f5790 100644 --- a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceMessage.java +++ b/src/main/java/com/limechain/network/protocol/blockannounce/messages/BlockAnnounceMessage.java @@ -1,4 +1,4 @@ -package com.limechain.network.protocol.blockannounce.scale; +package com.limechain.network.protocol.blockannounce.messages; import com.limechain.network.protocol.warp.dto.BlockHeader; import lombok.Getter; diff --git a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReader.java b/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReader.java index 116684805..c985b4ca2 100644 --- a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReader.java +++ b/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReader.java @@ -1,5 +1,6 @@ package com.limechain.network.protocol.blockannounce.scale; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleReader; import io.emeraldpay.polkaj.types.Hash256; diff --git a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleWriter.java b/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleWriter.java index 1009e65f7..5f0bff887 100644 --- a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleWriter.java +++ b/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleWriter.java @@ -1,5 +1,6 @@ package com.limechain.network.protocol.blockannounce.scale; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; import io.emeraldpay.polkaj.scale.ScaleCodecWriter; import io.emeraldpay.polkaj.scale.ScaleWriter; diff --git a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceMessageScaleReader.java b/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceMessageScaleReader.java index 0c234e54e..a15371136 100644 --- a/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceMessageScaleReader.java +++ b/src/main/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceMessageScaleReader.java @@ -1,5 +1,6 @@ package com.limechain.network.protocol.blockannounce.scale; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceMessage; import com.limechain.network.protocol.warp.scale.reader.BlockHeaderReader; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleReader; diff --git a/src/main/java/com/limechain/network/protocol/grandpa/GrandpaEngine.java b/src/main/java/com/limechain/network/protocol/grandpa/GrandpaEngine.java index fcba36b7d..0e34d4e76 100644 --- a/src/main/java/com/limechain/network/protocol/grandpa/GrandpaEngine.java +++ b/src/main/java/com/limechain/network/protocol/grandpa/GrandpaEngine.java @@ -1,6 +1,8 @@ package com.limechain.network.protocol.grandpa; +import com.limechain.exception.scale.ScaleEncodingException; import com.limechain.network.ConnectionManager; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshakeBuilder; import com.limechain.network.protocol.grandpa.messages.GrandpaMessageType; import com.limechain.network.protocol.grandpa.messages.catchup.req.CatchUpReqMessage; import com.limechain.network.protocol.grandpa.messages.catchup.req.CatchUpReqMessageScaleReader; @@ -9,16 +11,19 @@ import com.limechain.network.protocol.grandpa.messages.commit.CommitMessage; import com.limechain.network.protocol.grandpa.messages.commit.CommitMessageScaleReader; import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessage; +import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessageBuilder; import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessageScaleReader; import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessageScaleWriter; import com.limechain.network.protocol.grandpa.messages.vote.VoteMessage; import com.limechain.network.protocol.grandpa.messages.vote.VoteMessageScaleReader; -import com.limechain.exception.scale.ScaleEncodingException; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.rpc.server.AppBean; +import com.limechain.sync.warpsync.WarpSyncState; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleCodecWriter; import io.libp2p.core.PeerId; import io.libp2p.core.Stream; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.extern.java.Log; import java.io.ByteArrayOutputStream; @@ -29,11 +34,21 @@ * Engine for handling transactions on GRANDPA streams. */ @Log +@AllArgsConstructor(access = AccessLevel.PROTECTED) public class GrandpaEngine { private static final int HANDSHAKE_LENGTH = 1; - protected ConnectionManager connectionManager = ConnectionManager.getInstance(); - protected SyncedState syncedState = SyncedState.getInstance(); + protected ConnectionManager connectionManager; + protected WarpSyncState warpSyncState; + protected NeighbourMessageBuilder neighbourMessageBuilder; + protected BlockAnnounceHandshakeBuilder handshakeBuilder; + + public GrandpaEngine() { + connectionManager = ConnectionManager.getInstance(); + warpSyncState = AppBean.getBean(WarpSyncState.class); + neighbourMessageBuilder = new NeighbourMessageBuilder(); + handshakeBuilder = new BlockAnnounceHandshakeBuilder(); + } /** * Handles an incoming request as follows: @@ -44,7 +59,7 @@ public class GrandpaEngine { *

On responder stream: *

If message payload contains a valid handshake, adds the stream when the peer is not connected already, * ignore otherwise.

- *

On neighbour and commit messages, syncs received data using {@link SyncedState}.

+ *

On neighbour and commit messages, syncs received data using {@link WarpSyncState}.

*

Logs and ignores other message types.

* * @param message received message as byre array @@ -121,7 +136,7 @@ private void handleNeighbourMessage(byte[] message, PeerId peerId) { ScaleCodecReader reader = new ScaleCodecReader(message); NeighbourMessage neighbourMessage = reader.read(NeighbourMessageScaleReader.getInstance()); log.log(Level.INFO, "Received neighbour message from Peer " + peerId + "\n" + neighbourMessage); - new Thread(() -> syncedState.syncNeighbourMessage(neighbourMessage, peerId)).start(); + new Thread(() -> warpSyncState.syncNeighbourMessage(neighbourMessage, peerId)).start(); } private void handleVoteMessage(byte[] message, PeerId peerId) { @@ -134,7 +149,7 @@ private void handleVoteMessage(byte[] message, PeerId peerId) { private void handleCommitMessage(byte[] message, PeerId peerId) { ScaleCodecReader reader = new ScaleCodecReader(message); CommitMessage commitMessage = reader.read(CommitMessageScaleReader.getInstance()); - syncedState.syncCommit(commitMessage, peerId); + warpSyncState.syncCommit(commitMessage, peerId); } private void handleCatchupRequestMessage(byte[] message, PeerId peerId) { @@ -159,7 +174,7 @@ private void handleCatchupResponseMessage(byte[] message, PeerId peerId) { */ public void writeHandshakeToStream(Stream stream, PeerId peerId) { byte[] handshake = new byte[]{ - (byte) syncedState.getHandshake().getNodeRole() + (byte) handshakeBuilder.getBlockAnnounceHandshake().getNodeRole() }; log.log(Level.INFO, "Sending grandpa handshake to " + peerId); @@ -167,7 +182,7 @@ public void writeHandshakeToStream(Stream stream, PeerId peerId) { } /** - * Send our GRANDPA neighbour message from {@link SyncedState} on a given responder stream. + * Send our GRANDPA neighbour message from {@link WarpSyncState} on a given responder stream. * * @param stream responder stream to write the message to * @param peerId peer to send to @@ -175,7 +190,7 @@ public void writeHandshakeToStream(Stream stream, PeerId peerId) { public void writeNeighbourMessage(Stream stream, PeerId peerId) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); try (ScaleCodecWriter writer = new ScaleCodecWriter(buf)) { - writer.write(NeighbourMessageScaleWriter.getInstance(), syncedState.getNeighbourMessage()); + writer.write(NeighbourMessageScaleWriter.getInstance(), neighbourMessageBuilder.getNeighbourMessage()); } catch (IOException e) { throw new ScaleEncodingException(e); } diff --git a/src/main/java/com/limechain/network/protocol/grandpa/messages/neighbour/NeighbourMessageBuilder.java b/src/main/java/com/limechain/network/protocol/grandpa/messages/neighbour/NeighbourMessageBuilder.java new file mode 100644 index 000000000..772f1de0e --- /dev/null +++ b/src/main/java/com/limechain/network/protocol/grandpa/messages/neighbour/NeighbourMessageBuilder.java @@ -0,0 +1,20 @@ +package com.limechain.network.protocol.grandpa.messages.neighbour; + +import com.limechain.rpc.server.AppBean; +import com.limechain.storage.block.SyncState; + + +public class NeighbourMessageBuilder { + private static final int NEIGHBOUR_MESSAGE_VERSION = 1; + + public NeighbourMessage getNeighbourMessage() { + SyncState syncState = AppBean.getBean(SyncState.class); + + return new NeighbourMessage( + NEIGHBOUR_MESSAGE_VERSION, + syncState.getLatestRound(), + syncState.getSetId(), + syncState.getLastFinalizedBlockNumber() + ); + } +} diff --git a/src/main/java/com/limechain/network/protocol/sync/SyncMessages.java b/src/main/java/com/limechain/network/protocol/sync/SyncMessages.java index deefa85a0..1ac077cd5 100644 --- a/src/main/java/com/limechain/network/protocol/sync/SyncMessages.java +++ b/src/main/java/com/limechain/network/protocol/sync/SyncMessages.java @@ -28,7 +28,7 @@ public SyncMessage.BlockResponse remoteBlockRequest(Host us, AddressBook addrs, .sendBlockRequest(blockRequest.getFields(), blockRequest.getHash(), blockRequest.getNumber(), blockRequest.getDirection(), blockRequest.getMaxBlocks()) .get(2, TimeUnit.SECONDS); - log.log(Level.INFO, "Received blocks: " + response.getBlocksCount()); + log.log(Level.FINE, "Received blocks: " + response.getBlocksCount()); return response; } catch (ExecutionException | TimeoutException | IllegalStateException e) { log.log(Level.SEVERE, "Error while sending remote block request: ", e); diff --git a/src/main/java/com/limechain/network/protocol/transactions/TransactionsEngine.java b/src/main/java/com/limechain/network/protocol/transactions/TransactionsEngine.java index 6893679d5..57ed0b7d3 100644 --- a/src/main/java/com/limechain/network/protocol/transactions/TransactionsEngine.java +++ b/src/main/java/com/limechain/network/protocol/transactions/TransactionsEngine.java @@ -1,10 +1,10 @@ package com.limechain.network.protocol.transactions; +import com.limechain.exception.scale.ScaleEncodingException; import com.limechain.network.ConnectionManager; import com.limechain.network.protocol.transactions.scale.TransactionsReader; import com.limechain.network.protocol.transactions.scale.TransactionsWriter; -import com.limechain.exception.scale.ScaleEncodingException; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.sync.warpsync.WarpSyncState; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleCodecWriter; import io.libp2p.core.PeerId; @@ -23,7 +23,6 @@ public class TransactionsEngine { private static final int HANDSHAKE_LENGTH = 1; private final ConnectionManager connectionManager = ConnectionManager.getInstance(); - private final SyncedState syncedState = SyncedState.getInstance(); /** * Handles an incoming request as follows: @@ -34,7 +33,7 @@ public class TransactionsEngine { *

On responder stream: *

If message payload contains a valid handshake, adds the stream when the peer is not connected already, * ignore otherwise.

- *

On transactions messages {@link SyncedState}:

+ *

On transactions messages {@link WarpSyncState}:

*

Logs and ignores other message types.

* * @param message received message as byre array @@ -118,7 +117,7 @@ public void writeHandshakeToStream(Stream stream, PeerId peerId) { } /** - * Send our Transactions message from {@link SyncedState} on a given responder stream. + * Send our Transactions message from {@link WarpSyncState} on a given responder stream. * * @param stream responder stream to write the message to * @param peerId peer to send to diff --git a/src/main/java/com/limechain/rpc/client/AbstractRpcClient.java b/src/main/java/com/limechain/rpc/client/AbstractRpcClient.java index 0538632b2..59e3b5570 100644 --- a/src/main/java/com/limechain/rpc/client/AbstractRpcClient.java +++ b/src/main/java/com/limechain/rpc/client/AbstractRpcClient.java @@ -20,7 +20,7 @@ protected AbstractRpcClient(URI serverURI) { @Override public void onOpen(ServerHandshake handshake) { - log.log(Level.INFO, "new WS connection opened"); + log.log(Level.FINE, "new WS connection opened"); } @Override diff --git a/src/main/java/com/limechain/rpc/config/CommonConfig.java b/src/main/java/com/limechain/rpc/config/CommonConfig.java index 7a0cdab22..e644606e7 100644 --- a/src/main/java/com/limechain/rpc/config/CommonConfig.java +++ b/src/main/java/com/limechain/rpc/config/CommonConfig.java @@ -10,12 +10,12 @@ import com.limechain.network.Network; import com.limechain.rpc.server.UnsafeInterceptor; import com.limechain.storage.DBInitializer; -import com.limechain.storage.DBRepository; import com.limechain.storage.KVRepository; +import com.limechain.storage.block.SyncState; import com.limechain.storage.trie.TrieStorage; import com.limechain.sync.fullsync.FullSyncMachine; -import com.limechain.sync.warpsync.SyncedState; import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import org.springframework.boot.ApplicationArguments; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -51,10 +51,8 @@ public HostConfig hostConfig(CliArguments cliArgs) { @Bean public KVRepository repository(HostConfig hostConfig) { - DBRepository repository = DBInitializer.initialize(hostConfig.getRocksDbPath(), + return DBInitializer.initialize(hostConfig.getRocksDbPath(), hostConfig.getChain(), hostConfig.isDbRecreate()); - SyncedState.getInstance().setRepository(repository); - return repository; } @Bean @@ -68,8 +66,13 @@ public ChainService chainService(HostConfig hostConfig, KVRepository repository) { + return new SyncState(genesisBlockHash, repository); + } + + @Bean + public SystemInfo systemInfo(HostConfig hostConfig, Network network, SyncState syncState) { + return new SystemInfo(hostConfig, network, syncState); } @Bean @@ -79,17 +82,25 @@ public Network network(ChainService chainService, HostConfig hostConfig, KVRepos } @Bean - public WarpSyncMachine warpSyncMachine(Network network, ChainService chainService) { - return new WarpSyncMachine(network, chainService); + public WarpSyncState warpSyncState(Network network, SyncState syncState, + KVRepository repository) { + return new WarpSyncState(syncState, network, repository); } @Bean - public FullSyncMachine fullSyncMachine(Network network) { - return new FullSyncMachine(network); + public WarpSyncMachine warpSyncMachine(Network network, ChainService chainService, SyncState syncState, + WarpSyncState warpSyncState) { + return new WarpSyncMachine(network, chainService, syncState, warpSyncState); + } + + @Bean + public FullSyncMachine fullSyncMachine(Network network, SyncState syncState) { + return new FullSyncMachine(network, syncState); } @Bean public GenesisBlockHash genesisBlockHash(ChainService chainService) { return new GenesisBlockHash(chainService); } + } diff --git a/src/main/java/com/limechain/rpc/methods/system/SystemRPCImpl.java b/src/main/java/com/limechain/rpc/methods/system/SystemRPCImpl.java index 0fb860d49..60081c5a5 100644 --- a/src/main/java/com/limechain/rpc/methods/system/SystemRPCImpl.java +++ b/src/main/java/com/limechain/rpc/methods/system/SystemRPCImpl.java @@ -5,13 +5,13 @@ import com.limechain.chain.spec.PropertyValue; import com.limechain.config.SystemInfo; import com.limechain.exception.global.ExecutionFailedException; -import com.limechain.exception.rpc.PeerNotFoundException; import com.limechain.exception.global.ThreadInterruptedException; +import com.limechain.exception.rpc.PeerNotFoundException; import com.limechain.network.ConnectionManager; import com.limechain.network.Network; import com.limechain.network.dto.PeerInfo; import com.limechain.storage.block.BlockState; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.storage.block.SyncState; import com.limechain.sync.warpsync.WarpSyncMachine; import io.libp2p.core.PeerId; import lombok.AllArgsConstructor; @@ -40,7 +40,7 @@ public class SystemRPCImpl { private final SystemInfo systemInfo; private final Network network; private final WarpSyncMachine warpSync; - private final SyncedState syncedState = SyncedState.getInstance(); + private final SyncState syncState; private final BlockState blockState = BlockState.getInstance(); private final ConnectionManager connectionManager = ConnectionManager.getInstance(); @@ -189,8 +189,8 @@ public Map systemSyncState() { } return Map.ofEntries( - entry("startingBlock", this.syncedState.getStartingBlockNumber()), - entry("currentBlock", this.syncedState.getLastFinalizedBlockNumber()), + entry("startingBlock", this.syncState.getStartingBlock()), + entry("currentBlock", this.syncState.getLastFinalizedBlockNumber()), entry("highestBlock", highestBlock) ); } diff --git a/src/main/java/com/limechain/rpc/server/AppBean.java b/src/main/java/com/limechain/rpc/server/AppBean.java index 9dceb68cf..f6562b5fc 100644 --- a/src/main/java/com/limechain/rpc/server/AppBean.java +++ b/src/main/java/com/limechain/rpc/server/AppBean.java @@ -25,6 +25,10 @@ public class AppBean implements ApplicationContextAware { * Returns null otherwise. */ public static T getBean(Class beanClass) { + if (context == null) { + log.warning("Application context is not set"); + return null; + } try { return context.getBean(beanClass); } catch (NoSuchBeanDefinitionException e) { diff --git a/src/main/java/com/limechain/runtime/RuntimeBuilder.java b/src/main/java/com/limechain/runtime/RuntimeBuilder.java index 5d0b6730e..f0fc9a7b6 100644 --- a/src/main/java/com/limechain/runtime/RuntimeBuilder.java +++ b/src/main/java/com/limechain/runtime/RuntimeBuilder.java @@ -2,8 +2,6 @@ import com.github.luben.zstd.Zstd; import com.limechain.config.HostConfig; -import com.limechain.exception.global.RuntimeCodeException; -import com.limechain.exception.trie.TrieDecoderException; import com.limechain.network.Network; import com.limechain.network.protocol.blockannounce.NodeRole; import com.limechain.rpc.server.AppBean; @@ -21,11 +19,6 @@ import com.limechain.storage.offchain.StorageKind; import com.limechain.trie.AccessorHolder; import com.limechain.trie.BlockTrieAccessor; -import com.limechain.trie.decoded.Trie; -import com.limechain.trie.decoded.TrieVerifier; -import com.limechain.utils.LittleEndianUtils; -import com.limechain.utils.StringUtils; -import io.emeraldpay.polkaj.types.Hash256; import io.libp2p.core.Host; import lombok.extern.java.Log; import org.jetbrains.annotations.Nullable; @@ -218,32 +211,4 @@ public record Config( ) { public static final Config EMPTY = new Config(null, null, null, null, false); } - - // TODO: Move this method somewhere else as it doesn't have to do with actually building a runtime instance - private static final byte[] CODE_KEY_BYTES = - LittleEndianUtils.convertBytes(StringUtils.hexToBytes(StringUtils.toHex(":code"))); - - /** - * Builds and returns the runtime code based on decoded proofs and state root hash. - * - * @param decodedProofs The decoded trie proofs. - * @param stateRoot The state root hash. - * @return The runtime code. - * @throws RuntimeCodeException if an error occurs during the construction of the trie or retrieval of the code. - */ - public byte[] buildRuntimeCode(byte[][] decodedProofs, Hash256 stateRoot) { - try { - Trie trie = TrieVerifier.buildTrie(decodedProofs, stateRoot.getBytes()); - var code = trie.get(CODE_KEY_BYTES); - if (code == null) { - throw new RuntimeCodeException("Couldn't retrieve runtime code from trie"); - } - //TODO Heap pages should be fetched from out storage - log.log(Level.INFO, "Runtime and heap pages downloaded"); - return code; - - } catch (TrieDecoderException e) { - throw new RuntimeCodeException("Couldn't build trie from proofs list: " + e.getMessage()); - } - } } \ No newline at end of file diff --git a/src/main/java/com/limechain/runtime/hostapi/OffchainHostFunctions.java b/src/main/java/com/limechain/runtime/hostapi/OffchainHostFunctions.java index 3ccbda4bf..740e5fd7a 100644 --- a/src/main/java/com/limechain/runtime/hostapi/OffchainHostFunctions.java +++ b/src/main/java/com/limechain/runtime/hostapi/OffchainHostFunctions.java @@ -4,15 +4,14 @@ import com.limechain.exception.hostapi.InvalidArgumentException; import com.limechain.exception.hostapi.OffchainResponseWaitException; import com.limechain.exception.scale.ScaleEncodingException; -import com.limechain.network.Network; import com.limechain.runtime.SharedMemory; +import com.limechain.runtime.hostapi.dto.HttpErrorType; +import com.limechain.runtime.hostapi.dto.HttpStatusCode; +import com.limechain.runtime.hostapi.dto.InvalidRequestId; import com.limechain.runtime.hostapi.dto.OffchainNetworkState; import com.limechain.runtime.hostapi.dto.RuntimePointerSize; import com.limechain.storage.offchain.BasicStorage; import com.limechain.storage.offchain.OffchainStorages; -import com.limechain.runtime.hostapi.dto.HttpErrorType; -import com.limechain.runtime.hostapi.dto.HttpStatusCode; -import com.limechain.runtime.hostapi.dto.InvalidRequestId; import com.limechain.utils.scale.ScaleUtils; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleCodecWriter; @@ -197,9 +196,8 @@ public RuntimePointerSize extOffchainSubmitTransaction(RuntimePointerSize extrin * @see Opaque Network State */ public RuntimePointerSize extOffchainNetworkState() { - Network network = Network.getNetwork(); - PeerId peerId = network.getHost().getPeerId(); - List multiAddresses = network.getHost().listenAddresses(); + PeerId peerId = networkState.peerId(); + List multiAddresses = networkState.multiAddresses(); return sharedMemory.writeData(scaleEncodedOpaqueNetwork(peerId, multiAddresses)); } diff --git a/src/main/java/com/limechain/storage/DBConstants.java b/src/main/java/com/limechain/storage/DBConstants.java index c26f2b0f4..ba7d0bf13 100644 --- a/src/main/java/com/limechain/storage/DBConstants.java +++ b/src/main/java/com/limechain/storage/DBConstants.java @@ -13,20 +13,11 @@ public class DBConstants { * Key under which the genesis chain spec is stored */ public static final String GENESIS_KEY = "genesis"; - /** - * Key under which the latest sync state is stored - */ - public static final String SYNC_STATE_KEY = "syncState"; /** * Key under which the --latest-- state trie proof is stored * TODO: Currently only the latest loaded in sync is stored */ - public static final String STATE_TRIE_MERKLE_PROOF = "stateTrieProof"; - /** - * Key under which the --latest-- state trie root state is stored - * TODO: Currently only the latest loaded in sync is stored - */ - public static final String STATE_TRIE_ROOT_HASH = "stateTrieRootState"; + public static final String RUNTIME_CODE = "runtimeCode"; /** * Key under which the hash of the latest finalised block header is stored. @@ -37,4 +28,13 @@ public class DBConstants { * Key under which the highest round and set id is stored. */ public static final String HIGHEST_ROUND_AND_SET_ID_KEY = "hrs"; + + // SyncState keys + public static final String LAST_FINALIZED_BLOCK_NUMBER = "ss::lastFinalizedBlockNumber"; + public static final String LAST_FINALIZED_BLOCK_HASH = "ss::lastFinalizedBlockHash"; + public static final String AUTHORITY_SET = "ss::authoritySet"; + public static final String LATEST_ROUND = "ss::latestRound"; + public static final String STATE_ROOT = "ss::stateRoot"; + public static final String SET_ID = "ss::setId"; + // SyncState keys } diff --git a/src/main/java/com/limechain/storage/DBRepository.java b/src/main/java/com/limechain/storage/DBRepository.java index 2780ef523..5bd606c4d 100644 --- a/src/main/java/com/limechain/storage/DBRepository.java +++ b/src/main/java/com/limechain/storage/DBRepository.java @@ -16,11 +16,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.logging.Level; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Implementation for Key-Value DB interface with String as key and Object as value types */ @@ -35,7 +36,6 @@ public class DBRepository implements KVRepository { * Connection to the DB */ private RocksDB db; - private final String chainPrefix; public DBRepository(String path, String chain, boolean dbRecreate) { RocksDB.loadLibrary(); @@ -45,7 +45,6 @@ public DBRepository(String path, String chain, boolean dbRecreate) { if (dbRecreate) { cleanDatabaseFolder(baseDir); } - chainPrefix = chain; try { Files.createDirectories(baseDir.getParentFile().toPath()); Files.createDirectories(baseDir.getAbsoluteFile().toPath()); @@ -79,7 +78,7 @@ private void cleanDatabaseFolder(File file) { public synchronized boolean save(String key, Object value) { log.log(Level.FINE, String.format("saving value '%s' with key '%s'", value, key)); try { - db.put(getPrefixedKey(key), SerializationUtils.serialize(value)); + db.put(key.getBytes(UTF_8), SerializationUtils.serialize(value)); } catch (RocksDBException e) { log.log(Level.WARNING, String.format("Error saving entry. Cause: '%s', message: '%s'", e.getCause(), e.getMessage())); @@ -92,7 +91,7 @@ public synchronized boolean save(String key, Object value) { public synchronized Optional find(String key) { Object value = null; try { - byte[] bytes = db.get(getPrefixedKey(key)); + byte[] bytes = db.get(key.getBytes(UTF_8)); if (bytes != null) { value = SerializationUtils.deserialize(bytes); } @@ -112,7 +111,6 @@ public synchronized Optional find(String key) { public synchronized List findKeysByPrefix(String prefixSeek, int limit) { return findByPrefix(prefixSeek, (long) limit) .stream() - .map(this::removePrefixFromKey) .toList(); } @@ -120,7 +118,7 @@ public synchronized List findKeysByPrefix(String prefixSeek, int limit) public synchronized boolean delete(String key) { log.log(Level.FINE, String.format("deleting key '%s'", key)); try { - db.delete(getPrefixedKey(key)); + db.delete(key.getBytes(UTF_8)); } catch (RocksDBException e) { log.log(Level.SEVERE, String.format("Error deleting entry, cause: '%s', message: '%s'", e.getCause(), e.getMessage())); @@ -139,7 +137,7 @@ public synchronized DeleteByPrefixResult deleteByPrefix(String prefix, Long limi db.delete(key); } catch (RocksDBException e) { log.log(Level.SEVERE, String.format("Error deleting entry, cause: '%s', message: '%s'", - e.getCause(), e.getMessage())); + e.getCause(), e.getMessage())); } }); @@ -149,14 +147,12 @@ public synchronized DeleteByPrefixResult deleteByPrefix(String prefix, Long limi } private List findByPrefix(String prefix, Long limit) { - String prefixedKey = new String(getPrefixedKey(prefix)); - List values = new ArrayList<>(); RocksIterator rocksIterator = db.newIterator(); - rocksIterator.seek(prefixedKey.getBytes()); + rocksIterator.seek(prefix.getBytes()); while (rocksIterator.isValid() && (limit == null || values.size() < limit)) { byte[] key = rocksIterator.key(); - if (ByteArrayUtils.hasPrefix(key, prefixedKey.getBytes())) { + if (ByteArrayUtils.hasPrefix(key, prefix.getBytes())) { values.add(rocksIterator.key()); } rocksIterator.next(); @@ -169,7 +165,7 @@ private List findByPrefix(String prefix, Long limit) { @Override public synchronized Optional getNextKey(String key) { RocksIterator iterator = db.newIterator(); - iterator.seek(getPrefixedKey(key)); + iterator.seek(key.getBytes(UTF_8)); iterator.next(); String nextKey = iterator.isValid() ? new String(iterator.key()) : null; iterator.close(); @@ -191,13 +187,6 @@ public void commitTransaction() { //TODO: implement } - private byte[] getPrefixedKey(String key) { - return chainPrefix.concat(key).getBytes(); - } - public byte[] removePrefixFromKey(byte[] key) { - return Arrays.copyOfRange(key, chainPrefix.length(), key.length); - } - public synchronized void closeConnection() { this.db.close(); } diff --git a/src/main/java/com/limechain/storage/block/SyncState.java b/src/main/java/com/limechain/storage/block/SyncState.java new file mode 100644 index 000000000..416e2cd7d --- /dev/null +++ b/src/main/java/com/limechain/storage/block/SyncState.java @@ -0,0 +1,92 @@ +package com.limechain.storage.block; + +import com.limechain.chain.lightsyncstate.Authority; +import com.limechain.chain.lightsyncstate.LightSyncState; +import com.limechain.constants.GenesisBlockHash; +import com.limechain.network.protocol.grandpa.messages.commit.CommitMessage; +import com.limechain.network.protocol.warp.dto.Block; +import com.limechain.network.protocol.warp.dto.BlockHeader; +import com.limechain.storage.DBConstants; +import com.limechain.storage.KVRepository; +import io.emeraldpay.polkaj.types.Hash256; +import lombok.Getter; +import lombok.Setter; + +import java.math.BigInteger; + +@Getter +public class SyncState { + + private final GenesisBlockHash genesisBlockHashCalculator; + private final KVRepository repository; + private BigInteger lastFinalizedBlockNumber; + private final BigInteger startingBlock; + private final Hash256 genesisBlockHash; + private Hash256 lastFinalizedBlockHash; + @Setter + private Authority[] authoritySet; + private BigInteger latestRound; + private Hash256 stateRoot; + private BigInteger setId; + + public SyncState(GenesisBlockHash genesisBlockHashCalculator, KVRepository repository) { + this.genesisBlockHashCalculator = genesisBlockHashCalculator; + this.genesisBlockHash = genesisBlockHashCalculator.getGenesisHash(); + this.repository = repository; + + loadPersistedState(); + this.startingBlock = this.lastFinalizedBlockNumber; + } + + private void loadPersistedState() { + this.lastFinalizedBlockNumber = + (BigInteger) repository.find(DBConstants.LAST_FINALIZED_BLOCK_NUMBER).orElse(BigInteger.ZERO); + this.lastFinalizedBlockHash = new Hash256( + (byte[]) repository.find(DBConstants.LAST_FINALIZED_BLOCK_HASH).orElse(genesisBlockHash.getBytes())); + this.authoritySet = (Authority[]) repository.find(DBConstants.AUTHORITY_SET).orElse(new Authority[0]); + this.latestRound = (BigInteger) repository.find(DBConstants.LATEST_ROUND).orElse(BigInteger.ONE); + byte[] stateRootBytes = (byte[]) repository.find(DBConstants.STATE_ROOT).orElse(null); + this.stateRoot = stateRootBytes != null ? new Hash256(stateRootBytes) : null; + this.setId = (BigInteger) repository.find(DBConstants.SET_ID).orElse(BigInteger.ZERO); + } + + public void persistState() { + repository.save(DBConstants.LAST_FINALIZED_BLOCK_NUMBER, lastFinalizedBlockNumber); + repository.save(DBConstants.LAST_FINALIZED_BLOCK_HASH, lastFinalizedBlockHash.getBytes()); + repository.save(DBConstants.AUTHORITY_SET, authoritySet); + repository.save(DBConstants.LATEST_ROUND, latestRound); + repository.save(DBConstants.STATE_ROOT, stateRoot.getBytes()); + repository.save(DBConstants.SET_ID, setId); + } + + public void finalizeHeader(BlockHeader header) { + this.lastFinalizedBlockNumber = header.getBlockNumber(); + this.lastFinalizedBlockHash = header.getHash(); + this.stateRoot = header.getStateRoot(); + } + + public void finalizedCommitMessage(CommitMessage commitMessage) { + this.lastFinalizedBlockHash = commitMessage.getVote().getBlockHash(); + this.lastFinalizedBlockNumber = commitMessage.getVote().getBlockNumber(); + Block blockByHash = BlockState.getInstance().getBlockByHash(commitMessage.getVote().getBlockHash()); + if (blockByHash != null) { + this.stateRoot = blockByHash.getHeader().getStateRoot(); + } + } + + public BigInteger incrementSetId() { + this.setId = this.setId.add(BigInteger.ONE); + return setId; + } + + public void resetRound() { + this.latestRound = BigInteger.ONE; + } + + public void setLightSyncState(LightSyncState initState) { + this.setId = initState.getGrandpaAuthoritySet().getSetId(); + setAuthoritySet(initState.getGrandpaAuthoritySet().getCurrentAuthorities()); + finalizeHeader(initState.getFinalizedBlockHeader()); + } + +} diff --git a/src/main/java/com/limechain/sync/JustificationVerifier.java b/src/main/java/com/limechain/sync/JustificationVerifier.java index 16dc5c735..a947bf7c9 100644 --- a/src/main/java/com/limechain/sync/JustificationVerifier.java +++ b/src/main/java/com/limechain/sync/JustificationVerifier.java @@ -2,19 +2,17 @@ import com.limechain.chain.lightsyncstate.Authority; import com.limechain.network.protocol.warp.dto.Precommit; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.rpc.server.AppBean; +import com.limechain.runtime.hostapi.dto.Key; +import com.limechain.runtime.hostapi.dto.VerifySignature; +import com.limechain.storage.block.SyncState; +import com.limechain.utils.Ed25519Utils; import com.limechain.utils.LittleEndianUtils; import com.limechain.utils.StringUtils; -import io.emeraldpay.polkaj.scaletypes.Extrinsic; import io.emeraldpay.polkaj.types.Hash256; -import io.emeraldpay.polkaj.types.Hash512; -import io.libp2p.crypto.keys.Ed25519PublicKey; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.java.Log; -import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; -import org.bouncycastle.crypto.signers.Ed25519Signer; -import org.bouncycastle.util.encoders.Hex; import java.math.BigInteger; import java.nio.ByteBuffer; @@ -29,9 +27,9 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class JustificationVerifier { public static boolean verify(Precommit[] precommits, BigInteger round) { - SyncedState syncedState = SyncedState.getInstance(); - Authority[] authorities = syncedState.getAuthoritySet(); - BigInteger authoritiesSetId = syncedState.getSetId(); + SyncState syncState = AppBean.getBean(SyncState.class); + Authority[] authorities = syncState.getAuthoritySet(); + BigInteger authoritiesSetId = syncState.getSetId(); // Implementation from: https://github.com/smol-dot/smoldot // lib/src/finality/justification/verify.rs @@ -43,6 +41,7 @@ public static boolean verify(Precommit[] precommits, BigInteger round) { Set seenPublicKeys = new HashSet<>(); Set authorityKeys = Arrays.stream(authorities) .map(Authority::getPublicKey) + .map(Hash256::new) .collect(Collectors.toSet()); for (Precommit precommit : precommits) { @@ -109,22 +108,9 @@ private static byte[] getDataToVerify(Precommit precommit, BigInteger authoritie } public static boolean verifySignature(String publicKeyHex, String signatureHex, byte[] data) { - byte[] publicKeyBytes = Hex.decode(publicKeyHex.substring(2)); - byte[] signatureBytes = Hex.decode(signatureHex.substring(2)); - Ed25519PublicKeyParameters publicKeyParams = new Ed25519PublicKeyParameters(publicKeyBytes, 0); - Ed25519Signer verifier = new Ed25519Signer(); - verifier.init(false, publicKeyParams); - verifier.update(data, 0, data.length); - - Ed25519PublicKey publicKey = - new Ed25519PublicKey(publicKeyParams); - Extrinsic.ED25519Signature signature = new Extrinsic.ED25519Signature(Hash512.from(signatureHex)); - - boolean isValid = verifier.verifySignature(signatureBytes); - boolean result = publicKey.verify(data, signature.getValue().getBytes()); - if (!result) { - log.log(Level.WARNING, "Invalid signature"); - } - return isValid; + byte[] publicKeyBytes = StringUtils.hexToBytes(publicKeyHex); + byte[] signatureBytes = StringUtils.hexToBytes(signatureHex); + + return Ed25519Utils.verifySignature(new VerifySignature(signatureBytes, data, publicKeyBytes, Key.ED25519)); } } diff --git a/src/main/java/com/limechain/sync/fullsync/FullSyncMachine.java b/src/main/java/com/limechain/sync/fullsync/FullSyncMachine.java index 86e862ab5..846049e13 100644 --- a/src/main/java/com/limechain/sync/fullsync/FullSyncMachine.java +++ b/src/main/java/com/limechain/sync/fullsync/FullSyncMachine.java @@ -17,6 +17,7 @@ import com.limechain.runtime.RuntimeBuilder; import com.limechain.runtime.version.StateVersion; import com.limechain.storage.block.BlockState; +import com.limechain.storage.block.SyncState; import com.limechain.sync.fullsync.inherents.InherentData; import com.limechain.sync.fullsync.inherents.scale.InherentDataWriter; import com.limechain.trie.AccessorHolder; @@ -42,12 +43,14 @@ @Log public class FullSyncMachine { private final Network networkService; + private final SyncState syncState; private final BlockState blockState = BlockState.getInstance(); private final AccessorHolder accessorHolder = AccessorHolder.getInstance(); private Runtime runtime = null; - public FullSyncMachine(final Network networkService) { + public FullSyncMachine(final Network networkService, final SyncState syncState) { this.networkService = networkService; + this.syncState = syncState; } public void start() { @@ -56,6 +59,10 @@ public void start() { // unless explicitly set via some of the "update..." methods this.networkService.updateCurrentSelectedPeerWithNextBootnode(); + Hash256 lastFinelizedStateRoot = syncState.getStateRoot(); //to replace line 67 + // TODO: fetch state of the latest finalized block and start executing blocks from there + // scrap the blockstate highest finalized header logic for now + BlockHeader highestFinalizedHeader = blockState.getHighestFinalizedHeader(); Hash256 stateRoot = highestFinalizedHeader.getStateRoot(); accessorHolder.setToStateRoot(stateRoot.getBytes()); diff --git a/src/main/java/com/limechain/sync/warpsync/WarpSyncMachine.java b/src/main/java/com/limechain/sync/warpsync/WarpSyncMachine.java index acc509be2..a3eaecdbf 100644 --- a/src/main/java/com/limechain/sync/warpsync/WarpSyncMachine.java +++ b/src/main/java/com/limechain/sync/warpsync/WarpSyncMachine.java @@ -3,13 +3,12 @@ import com.limechain.chain.ChainService; import com.limechain.chain.lightsyncstate.Authority; import com.limechain.chain.lightsyncstate.LightSyncState; -import com.limechain.constants.GenesisBlockHash; import com.limechain.network.Network; import com.limechain.network.protocol.warp.dto.WarpSyncFragment; -import com.limechain.rpc.server.AppBean; -import com.limechain.sync.warpsync.state.FinishedState; -import com.limechain.sync.warpsync.state.RequestFragmentsState; -import com.limechain.sync.warpsync.state.WarpSyncState; +import com.limechain.storage.block.SyncState; +import com.limechain.sync.warpsync.action.FinishedAction; +import com.limechain.sync.warpsync.action.RequestFragmentsAction; +import com.limechain.sync.warpsync.action.WarpSyncAction; import io.emeraldpay.polkaj.types.Hash256; import lombok.Getter; import lombok.Setter; @@ -17,7 +16,9 @@ import org.javatuples.Pair; import java.math.BigInteger; +import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.PriorityQueue; import java.util.Queue; import java.util.concurrent.ExecutorService; @@ -25,85 +26,86 @@ import java.util.logging.Level; @Log +@Getter +@Setter public class WarpSyncMachine { + + private final PriorityQueue> scheduledAuthorityChanges; + private final ChainInformation chainInformation; + private Queue fragmentsQueue; private final ChainService chainService; - @Getter + private final ExecutorService executor; + private WarpSyncAction warpSyncAction; + private final WarpSyncState warpState; private final Network networkService; - @Getter - private final SyncedState syncedState = SyncedState.getInstance(); - private final ExecutorService executor = Executors.newSingleThreadExecutor(); - private final boolean stateLoaded; - @Setter - private WarpSyncState warpSyncState; - @Getter - @Setter - private Queue fragmentsQueue; - @Getter - @Setter - private PriorityQueue> scheduledAuthorityChanges = - new PriorityQueue<>(Comparator.comparing(Pair::getValue0)); - @Getter - private ChainInformation chainInformation = new ChainInformation(); - - public WarpSyncMachine(Network network, ChainService chainService) { + private final SyncState syncState; + private final List onFinishCallbacks; + + public WarpSyncMachine(Network network, ChainService chainService, SyncState syncState, WarpSyncState warpSyncState) { this.networkService = network; this.chainService = chainService; - syncedState.setNetwork(network); + this.syncState = syncState; - this.stateLoaded = this.syncedState.loadState(); + this.warpState = warpSyncState; + this.executor = Executors.newSingleThreadExecutor(); + this.scheduledAuthorityChanges = new PriorityQueue<>(Comparator.comparing(Pair::getValue0)); + this.chainInformation = new ChainInformation(); + this.onFinishCallbacks = new ArrayList<>(); } public void nextState() { - warpSyncState.next(this); + warpSyncAction.next(this); } public void handleState() { - warpSyncState.handle(this); + warpSyncAction.handle(this); } public boolean isSyncing() { - return this.warpSyncState.getClass() != FinishedState.class; + return this.warpSyncAction.getClass() != FinishedAction.class; } public void start() { - GenesisBlockHash genesisBlockHash = AppBean.getBean(GenesisBlockHash.class); - final Hash256 initStateHash; - - if (stateLoaded) { - initStateHash = this.syncedState.getLastFinalizedBlockHash(); - } else if (this.chainService.getChainSpec().getLightSyncState() != null) { + if (this.chainService.getChainSpec().getLightSyncState() != null) { LightSyncState initState = LightSyncState.decode(this.chainService.getChainSpec().getLightSyncState()); - initStateHash = initState.getFinalizedBlockHeader().getParentHash(); - this.syncedState.setAuthoritySet(initState.getGrandpaAuthoritySet().getCurrentAuthorities()); - this.syncedState.setSetId(initState.getGrandpaAuthoritySet().getSetId()); - } else { - initStateHash = genesisBlockHash.getGenesisHash(); + if (this.syncState.getLastFinalizedBlockNumber() + .compareTo(initState.getFinalizedBlockHeader().getBlockNumber()) < 0) { + this.syncState.setLightSyncState(initState); + } } + final Hash256 initStateHash = this.syncState.getLastFinalizedBlockHash(); // Always start with requesting fragments log.log(Level.INFO, "Requesting fragments..."); this.networkService.updateCurrentSelectedPeerWithNextBootnode(); - this.warpSyncState = new RequestFragmentsState(initStateHash); + this.warpSyncAction = new RequestFragmentsAction(initStateHash); executor.submit(() -> { - while (this.warpSyncState.getClass() != FinishedState.class) { + while (this.warpSyncAction.getClass() != FinishedAction.class) { this.handleState(); this.nextState(); } - startFullSync(); + finishWarpSync(); }); } public void stop() { log.info("Stopping warp sync machine"); executor.shutdown(); - this.warpSyncState = null; + this.warpSyncAction = null; log.info("Warp sync machine stopped."); } - private void startFullSync() { - this.syncedState.setWarpSyncFinished(true); + private void finishWarpSync() { + this.warpState.setWarpSyncFinished(true); this.networkService.handshakeBootNodes(); + this.syncState.persistState(); + log.info("Warp sync finished."); + this.onFinishCallbacks.forEach(executor::submit); + } + + public void onFinish(Runnable function) { + onFinishCallbacks.add(function); } } diff --git a/src/main/java/com/limechain/sync/warpsync/SyncedState.java b/src/main/java/com/limechain/sync/warpsync/WarpSyncState.java similarity index 64% rename from src/main/java/com/limechain/sync/warpsync/SyncedState.java rename to src/main/java/com/limechain/sync/warpsync/WarpSyncState.java index c50b6c468..1ca001594 100644 --- a/src/main/java/com/limechain/sync/warpsync/SyncedState.java +++ b/src/main/java/com/limechain/sync/warpsync/WarpSyncState.java @@ -1,11 +1,10 @@ package com.limechain.sync.warpsync; import com.limechain.chain.lightsyncstate.Authority; -import com.limechain.constants.GenesisBlockHash; import com.limechain.exception.global.RuntimeCodeException; +import com.limechain.exception.trie.TrieDecoderException; import com.limechain.network.Network; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshake; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessage; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceMessage; import com.limechain.network.protocol.grandpa.messages.commit.CommitMessage; import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessage; import com.limechain.network.protocol.lightclient.pb.LightClientMessage; @@ -18,25 +17,24 @@ import com.limechain.network.protocol.warp.dto.Justification; import com.limechain.network.protocol.warp.scale.reader.BlockHeaderReader; import com.limechain.network.protocol.warp.scale.reader.JustificationReader; -import com.limechain.rpc.server.AppBean; import com.limechain.runtime.Runtime; import com.limechain.runtime.RuntimeBuilder; import com.limechain.storage.DBConstants; import com.limechain.storage.KVRepository; -import com.limechain.storage.block.BlockState; +import com.limechain.storage.block.SyncState; import com.limechain.sync.JustificationVerifier; import com.limechain.sync.warpsync.dto.AuthoritySetChange; import com.limechain.sync.warpsync.dto.GrandpaDigestMessageType; -import com.limechain.sync.warpsync.dto.StateDto; import com.limechain.sync.warpsync.scale.ForcedChangeReader; import com.limechain.sync.warpsync.scale.ScheduledChangeReader; +import com.limechain.trie.decoded.Trie; +import com.limechain.trie.decoded.TrieVerifier; +import com.limechain.utils.LittleEndianUtils; import com.limechain.utils.StringUtils; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.types.Hash256; import io.libp2p.core.PeerId; -import lombok.AccessLevel; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.java.Log; import org.javatuples.Pair; @@ -45,8 +43,6 @@ import java.util.Arrays; import java.util.Comparator; import java.util.HashSet; -import java.util.List; -import java.util.Optional; import java.util.PriorityQueue; import java.util.Set; import java.util.logging.Level; @@ -54,73 +50,49 @@ /** * Singleton class, holds and handles the synced state of the Host. */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) -@Getter -@Setter @Log -public class SyncedState { - public static final int NEIGHBOUR_MESSAGE_VERSION = 1; +@Setter +public class WarpSyncState { + + private final SyncState syncState; + private final Network network; + private final KVRepository db; + public static final String CODE_KEY = StringUtils.toHex(":code"); - private static final SyncedState INSTANCE = new SyncedState(); - private final PriorityQueue> scheduledAuthorityChanges = - new PriorityQueue<>(Comparator.comparing(Pair::getValue0)); + + @Getter private boolean warpSyncFragmentsFinished; + @Getter private boolean warpSyncFinished; - private BigInteger startingBlockNumber = BigInteger.ZERO; - private BigInteger lastFinalizedBlockNumber = BigInteger.ZERO; - private Hash256 lastFinalizedBlockHash; - private Hash256 stateRoot; - - private Authority[] authoritySet; - private BigInteger setId = BigInteger.ZERO; - private BigInteger latestRound = BigInteger.ONE; - + @Getter private Runtime runtime; + @Getter private byte[] runtimeCode; - private byte[] heapPages; - private KVRepository repository; - private Network network; - private RuntimeBuilder runtimeBuilder = new RuntimeBuilder(); - private BlockState blockState; - private Set scheduledRuntimeUpdateBlocks = new HashSet<>(); + protected final RuntimeBuilder runtimeBuilder; + private final Set scheduledRuntimeUpdateBlocks; + private final PriorityQueue> scheduledAuthorityChanges; - public static SyncedState getInstance() { - return INSTANCE; - } - /** - * Creates a Block Announce handshake based on the latest finalized Host state - * - * @return our Block Announce handshake - */ - public BlockAnnounceHandshake getHandshake() { - Hash256 genesisBlockHash = AppBean.getBean(GenesisBlockHash.class).getGenesisHash(); - - Hash256 blockHash = this.lastFinalizedBlockHash == null - ? genesisBlockHash - : this.lastFinalizedBlockHash; - return new BlockAnnounceHandshake( - network.getNodeRole().getValue(), - this.lastFinalizedBlockNumber, - blockHash, - genesisBlockHash - ); + public WarpSyncState(SyncState syncState, Network network, KVRepository db) { + this(syncState, + network, + db, + new RuntimeBuilder(), + new HashSet<>(), + new PriorityQueue<>(Comparator.comparing(Pair::getValue0))); } - /** - * Creates a GRANDPA handshake based on the latest finalized Host state - * - * @return our GRANDPA handshake - */ - public NeighbourMessage getNeighbourMessage() { - return new NeighbourMessage( - NEIGHBOUR_MESSAGE_VERSION, - this.latestRound, - this.setId, - this.lastFinalizedBlockNumber - ); + public WarpSyncState(SyncState syncState, Network network, KVRepository db, + RuntimeBuilder runtimeBuilder, Set scheduledRuntimeUpdateBlocks, + PriorityQueue> scheduledAuthorityChanges) { + this.syncState = syncState; + this.network = network; + this.db = db; + this.runtimeBuilder = runtimeBuilder; + this.scheduledRuntimeUpdateBlocks = scheduledRuntimeUpdateBlocks; + this.scheduledAuthorityChanges = scheduledAuthorityChanges; } /** @@ -147,7 +119,7 @@ public void syncBlockAnnounce(BlockAnnounceMessage blockAnnounceMessage) { * @param peerId sender of the message */ public synchronized void syncCommit(CommitMessage commitMessage, PeerId peerId) { - if (commitMessage.getVote().getBlockNumber().compareTo(lastFinalizedBlockNumber) <= 0) { + if (commitMessage.getVote().getBlockNumber().compareTo(syncState.getLastFinalizedBlockNumber()) <= 0) { log.log(Level.FINE, String.format("Received commit message for finalized block %d from peer %s", commitMessage.getVote().getBlockNumber(), peerId)); return; @@ -171,32 +143,60 @@ public synchronized void syncCommit(CommitMessage commitMessage, PeerId peerId) } private void updateState(CommitMessage commitMessage) { + BigInteger lastFinalizedBlockNumber = syncState.getLastFinalizedBlockNumber(); if (commitMessage.getVote().getBlockNumber().compareTo(lastFinalizedBlockNumber) < 1) { return; } - final Hash256 blockHash = commitMessage.getVote().getBlockHash(); + syncState.finalizedCommitMessage(commitMessage); - latestRound = commitMessage.getRoundNumber(); - lastFinalizedBlockHash = blockHash; - lastFinalizedBlockNumber = commitMessage.getVote().getBlockNumber(); log.log(Level.INFO, "Reached block #" + lastFinalizedBlockNumber); if (warpSyncFinished && scheduledRuntimeUpdateBlocks.contains(lastFinalizedBlockNumber)) { - new Thread(() -> updateRuntime(blockHash)).start(); + new Thread(this::updateRuntime).start(); } - persistState(); } - private void updateRuntime(Hash256 blockHash) { + private void updateRuntime() { updateRuntimeCode(); - buildRuntime(blockHash); + buildRuntime(); + BigInteger lastFinalizedBlockNumber = syncState.getLastFinalizedBlockNumber(); scheduledRuntimeUpdateBlocks.remove(lastFinalizedBlockNumber); } + private static final byte[] CODE_KEY_BYTES = + LittleEndianUtils.convertBytes(StringUtils.hexToBytes(StringUtils.toHex(":code"))); + + /** + * Builds and returns the runtime code based on decoded proofs and state root hash. + * + * @param decodedProofs The decoded trie proofs. + * @param stateRoot The state root hash. + * @return The runtime code. + * @throws RuntimeCodeException if an error occurs during the construction of the trie or retrieval of the code. + */ + public byte[] buildRuntimeCode(byte[][] decodedProofs, Hash256 stateRoot) { + try { + Trie trie = TrieVerifier.buildTrie(decodedProofs, stateRoot.getBytes()); + var code = trie.get(CODE_KEY_BYTES); + if (code == null) { + throw new RuntimeCodeException("Couldn't retrieve runtime code from trie"); + } + //TODO Heap pages should be fetched from out storage + log.log(Level.INFO, "Runtime and heap pages downloaded"); + return code; + + } catch (TrieDecoderException e) { + throw new RuntimeCodeException("Couldn't build trie from proofs list: " + e.getMessage()); + } + } + /** * Update the runtime code and heap pages, by requesting the code field of the last finalized block, using the * Light Messages protocol. */ public void updateRuntimeCode() { + Hash256 lastFinalizedBlockHash = syncState.getLastFinalizedBlockHash(); + Hash256 stateRoot = syncState.getStateRoot(); + LightClientMessage.Response response = network.makeRemoteReadRequest( lastFinalizedBlockHash.toString(), new String[]{CODE_KEY} @@ -205,9 +205,9 @@ public void updateRuntimeCode() { byte[] proof = response.getRemoteReadResponse().getProof().toByteArray(); byte[][] decodedProofs = decodeProof(proof); - saveProofState(decodedProofs); + this.runtimeCode = buildRuntimeCode(decodedProofs, stateRoot); - this.runtimeCode = runtimeBuilder.buildRuntimeCode(decodedProofs, stateRoot); + saveRuntimeCode(runtimeCode); } private byte[][] decodeProof(byte[] proof) { @@ -221,20 +221,16 @@ private byte[][] decodeProof(byte[] proof) { return decodedProofs; } - private void saveProofState(byte[][] proof) { - repository.save(DBConstants.STATE_TRIE_MERKLE_PROOF, proof); - repository.save(DBConstants.STATE_TRIE_ROOT_HASH, stateRoot.toString()); + private void saveRuntimeCode(byte[] runtimeCode) { + db.save(DBConstants.RUNTIME_CODE, runtimeCode); } /** * Build the runtime from the available runtime code. */ - public void buildRuntime(Hash256 blockHash) { + public void buildRuntime() { try { runtime = runtimeBuilder.buildRuntime(runtimeCode); - if (BlockState.getInstance().isInitialized()) { - BlockState.getInstance().storeRuntime(blockHash, runtime); - } } catch (UnsatisfiedLinkError e) { log.log(Level.SEVERE, "Error loading wasm module"); log.log(Level.SEVERE, e.getMessage(), e.getStackTrace()); @@ -248,13 +244,8 @@ public void buildRuntime(Hash256 blockHash) { * Load a saved runtime from database */ public void loadSavedRuntimeCode() { - byte[][] merkleProof = (byte[][]) repository.find(DBConstants.STATE_TRIE_MERKLE_PROOF) - .orElseThrow(() -> new RuntimeCodeException("No available merkle proof")); - Hash256 stateRootDecoded = repository.find(DBConstants.STATE_TRIE_ROOT_HASH) - .map(storedRootState -> Hash256.from(storedRootState.toString())) - .orElseThrow(() -> new RuntimeCodeException("No available state root")); - - this.runtimeCode = runtimeBuilder.buildRuntimeCode(merkleProof, stateRootDecoded); + this.runtimeCode = (byte[]) db.find(DBConstants.RUNTIME_CODE) + .orElseThrow(() -> new RuntimeCodeException("No available runtime code")); } /** @@ -267,7 +258,7 @@ public void loadSavedRuntimeCode() { */ public void syncNeighbourMessage(NeighbourMessage neighbourMessage, PeerId peerId) { network.sendNeighbourMessage(peerId); - if (warpSyncFinished && neighbourMessage.getSetId().compareTo(setId) > 0) { + if (warpSyncFinished && neighbourMessage.getSetId().compareTo(syncState.getSetId()) > 0) { updateSetData(neighbourMessage.getLastFinalizedBlock().add(BigInteger.ONE), peerId); } } @@ -288,12 +279,10 @@ private void updateSetData(BigInteger setChangeBlock, PeerId peerId) { if (verified) { BlockHeader header = new BlockHeaderReader().read(new ScaleCodecReader(block.getHeader().toByteArray())); - this.lastFinalizedBlockNumber = header.getBlockNumber(); - this.lastFinalizedBlockHash = header.getHash(); + syncState.finalizeHeader(header); handleAuthorityChanges(header.getDigest(), setChangeBlock); handleScheduledEvents(); - persistState(); } } @@ -302,12 +291,13 @@ private void updateSetData(BigInteger setChangeBlock, PeerId peerId) { */ public void handleScheduledEvents() { Pair data = scheduledAuthorityChanges.peek(); + BigInteger setId = syncState.getSetId(); boolean updated = false; while (data != null) { - if (data.getValue0().compareTo(this.getLastFinalizedBlockNumber()) < 1) { - authoritySet = data.getValue1(); - setId = setId.add(BigInteger.ONE); - latestRound = BigInteger.ONE; + if (data.getValue0().compareTo(syncState.getLastFinalizedBlockNumber()) < 1) { + setId = syncState.incrementSetId(); + syncState.resetRound(); + syncState.setAuthoritySet(data.getValue1()); scheduledAuthorityChanges.poll(); updated = true; } else break; @@ -315,7 +305,7 @@ public void handleScheduledEvents() { } if (warpSyncFinished && updated) { log.log(Level.INFO, "Successfully transitioned to authority set id: " + setId); - new Thread(() -> network.sendNeighbourMessages()).start(); + new Thread(network::sendNeighbourMessages).start(); } } @@ -372,53 +362,4 @@ public void handleAuthorityChanges(HeaderDigest[] headerDigests, BigInteger bloc } } - /** - * Persists the Host's current state to the DB. - */ - public void persistState() { - List> authorities = Arrays - .stream(authoritySet) - .map(authority -> { - String key = authority.getPublicKey().toString(); - BigInteger weight = authority.getWeight(); - return new Pair<>(key, weight); - }).toList(); - - StateDto stateDto = new StateDto( - latestRound, - lastFinalizedBlockHash.toString(), - lastFinalizedBlockNumber, - authorities, - setId - ); - repository.save(DBConstants.SYNC_STATE_KEY, stateDto); - } - - /** - * Loads the Host's saved state from the DB. - * - * @return is the state loaded successfully - */ - public boolean loadState() { - Optional syncState = repository.find(DBConstants.SYNC_STATE_KEY); - if (syncState.isPresent() && syncState.get() instanceof StateDto state) { - this.latestRound = state.latestRound(); - this.lastFinalizedBlockHash = Hash256.from(state.lastFinalizedBlockHash()); - this.lastFinalizedBlockNumber = state.lastFinalizedBlockNumber(); - this.startingBlockNumber = lastFinalizedBlockNumber; - this.authoritySet = state.authoritySet() - .stream() - .map(pair -> { - Hash256 publicKey = Hash256.from(pair.getValue0()); - BigInteger weight = pair.getValue1(); - return new Authority(publicKey, weight); - }).toArray(Authority[]::new); - - this.setId = state.setId(); - - return true; - } - return false; - } - } \ No newline at end of file diff --git a/src/main/java/com/limechain/sync/warpsync/state/ChainInformationBuildState.java b/src/main/java/com/limechain/sync/warpsync/action/ChainInformationBuildAction.java similarity index 53% rename from src/main/java/com/limechain/sync/warpsync/state/ChainInformationBuildState.java rename to src/main/java/com/limechain/sync/warpsync/action/ChainInformationBuildAction.java index e131dda39..347ef124b 100644 --- a/src/main/java/com/limechain/sync/warpsync/state/ChainInformationBuildState.java +++ b/src/main/java/com/limechain/sync/warpsync/action/ChainInformationBuildAction.java @@ -1,9 +1,12 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; +import com.limechain.rpc.server.AppBean; import com.limechain.runtime.version.ApiVersion; -import com.limechain.sync.warpsync.SyncedState; import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import com.limechain.utils.HashUtils; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.extern.java.Log; import java.util.logging.Level; @@ -12,13 +15,18 @@ * Sets consensus protocol versions */ @Log -public class ChainInformationBuildState implements WarpSyncState { - private final SyncedState syncedState = SyncedState.getInstance(); +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class ChainInformationBuildAction implements WarpSyncAction { + private final WarpSyncState warpSyncState; + + public ChainInformationBuildAction() { + warpSyncState = AppBean.getBean(WarpSyncState.class); + } @Override public void next(WarpSyncMachine sync) { log.log(Level.INFO, "Done with runtime build"); - sync.setWarpSyncState(new ChainInformationDownloadState()); + sync.setWarpSyncAction(new ChainInformationDownloadAction()); } @Override @@ -29,17 +37,17 @@ public void handle(WarpSyncMachine sync) { HashUtils.hashWithBlake2bToLength("GrandpaApi".getBytes(), ApiVersion.NAME_HASH_LENGTH) }; sync.getChainInformation().setRuntimeAuraVersion( - syncedState.getRuntime().getVersion().getApis().getApiVersion(hashedApiVersions[0])); + warpSyncState.getRuntime().getVersion().getApis().getApiVersion(hashedApiVersions[0])); sync.getChainInformation().setRuntimeBabeVersion( - syncedState.getRuntime().getVersion().getApis().getApiVersion(hashedApiVersions[1])); + warpSyncState.getRuntime().getVersion().getApis().getApiVersion(hashedApiVersions[1])); sync.getChainInformation().setRuntimeGrandpaVersion( - syncedState.getRuntime().getVersion().getApis().getApiVersion(hashedApiVersions[2])); + warpSyncState.getRuntime().getVersion().getApis().getApiVersion(hashedApiVersions[2])); log.log(Level.INFO, "Aura Api version: " + sync.getChainInformation().getRuntimeAuraVersion() - + " Babe api version: " + sync.getChainInformation().getRuntimeBabeVersion() + - " Grandpa Api Version: " + sync.getChainInformation().getRuntimeGrandpaVersion()); + + " Babe api version: " + sync.getChainInformation().getRuntimeBabeVersion() + + " Grandpa Api Version: " + sync.getChainInformation().getRuntimeGrandpaVersion()); log.log(Level.INFO, "Runtime supports aura: " + sync.getChainInformation().runtimeHasAura()); log.log(Level.INFO, "Runtime babe api is v1: " + sync.getChainInformation().runtimeBabeApiIsV1()); log.log(Level.INFO, "Runtime grandpa supports current setId: " - + sync.getChainInformation().runtimeGrandpaSupportsCurrentSetId()); + + sync.getChainInformation().runtimeGrandpaSupportsCurrentSetId()); } } diff --git a/src/main/java/com/limechain/sync/warpsync/state/ChainInformationDownloadState.java b/src/main/java/com/limechain/sync/warpsync/action/ChainInformationDownloadAction.java similarity index 91% rename from src/main/java/com/limechain/sync/warpsync/state/ChainInformationDownloadState.java rename to src/main/java/com/limechain/sync/warpsync/action/ChainInformationDownloadAction.java index 6c5e22e2f..72f43f606 100644 --- a/src/main/java/com/limechain/sync/warpsync/state/ChainInformationDownloadState.java +++ b/src/main/java/com/limechain/sync/warpsync/action/ChainInformationDownloadAction.java @@ -1,4 +1,4 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; import com.limechain.sync.warpsync.WarpSyncMachine; import lombok.extern.java.Log; @@ -11,7 +11,7 @@ * be downloaded from a source in the Chain Information Download State */ @Log -public class ChainInformationDownloadState implements WarpSyncState { +public class ChainInformationDownloadAction implements WarpSyncAction { private String[] runtimeFunctionCalls = new String[]{ "AuraApi_slot_duration", "AuraApi_authorities", @@ -25,7 +25,7 @@ public class ChainInformationDownloadState implements WarpSyncState { @Override public void next(WarpSyncMachine sync) { // We're done with the warp sync process! - sync.setWarpSyncState(new FinishedState()); + sync.setWarpSyncAction(new FinishedAction()); } @Override diff --git a/src/main/java/com/limechain/sync/warpsync/state/FinishedState.java b/src/main/java/com/limechain/sync/warpsync/action/FinishedAction.java similarity index 59% rename from src/main/java/com/limechain/sync/warpsync/state/FinishedState.java rename to src/main/java/com/limechain/sync/warpsync/action/FinishedAction.java index 6343126e6..d084d57a2 100644 --- a/src/main/java/com/limechain/sync/warpsync/state/FinishedState.java +++ b/src/main/java/com/limechain/sync/warpsync/action/FinishedAction.java @@ -1,21 +1,23 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.rpc.server.AppBean; import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import lombok.extern.java.Log; import java.util.logging.Level; @Log -public class FinishedState implements WarpSyncState { - private final SyncedState syncedState = SyncedState.getInstance(); - public FinishedState() { +public class FinishedAction implements WarpSyncAction { + private final WarpSyncState warpSyncState; + public FinishedAction() { + this.warpSyncState = AppBean.getBean(WarpSyncState.class); log.log(Level.INFO, "Finished with warp sync!"); } @Override public void next(WarpSyncMachine sync) { - syncedState.getRuntime().close(); + warpSyncState.getRuntime().close(); log.log(Level.INFO, "Closed sync runtime instance."); log.log(Level.INFO, "Finished! Finished with warp sync! Nothing to execute."); } diff --git a/src/main/java/com/limechain/sync/warpsync/state/RequestFragmentsState.java b/src/main/java/com/limechain/sync/warpsync/action/RequestFragmentsAction.java similarity index 78% rename from src/main/java/com/limechain/sync/warpsync/state/RequestFragmentsState.java rename to src/main/java/com/limechain/sync/warpsync/action/RequestFragmentsAction.java index af00b14e0..e3ff6a483 100644 --- a/src/main/java/com/limechain/sync/warpsync/state/RequestFragmentsState.java +++ b/src/main/java/com/limechain/sync/warpsync/action/RequestFragmentsAction.java @@ -1,9 +1,10 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; import com.limechain.exception.global.MissingObjectException; import com.limechain.network.protocol.warp.dto.WarpSyncResponse; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.rpc.server.AppBean; import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import io.emeraldpay.polkaj.types.Hash256; import lombok.extern.java.Log; @@ -12,15 +13,16 @@ import java.util.logging.Level; @Log -public class RequestFragmentsState implements WarpSyncState { +public class RequestFragmentsAction implements WarpSyncAction { - private final SyncedState syncedState = SyncedState.getInstance(); + private final WarpSyncState warpSyncState; private final Hash256 blockHash; private WarpSyncResponse result; private Exception error; - public RequestFragmentsState(Hash256 blockHash) { + public RequestFragmentsAction(Hash256 blockHash) { this.blockHash = blockHash; + this.warpSyncState = AppBean.getBean(WarpSyncState.class); } @Override @@ -30,16 +32,16 @@ public void next(WarpSyncMachine sync) { try { // Wait a bit before retrying. The peer might've just connected and still not in address book Thread.sleep(1000); - sync.setWarpSyncState(new RequestFragmentsState(blockHash)); + sync.setWarpSyncAction(new RequestFragmentsAction(blockHash)); return; } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.log(Level.SEVERE, "Retry warp sync request fragment exception: " - + e.getMessage(), e.getStackTrace()); + + e.getMessage(), e.getStackTrace()); } } if (this.result != null) { - sync.setWarpSyncState(new VerifyJustificationState()); + sync.setWarpSyncAction(new VerifyJustificationAction()); return; } log.log(Level.WARNING, "RequestFragmentsState.next() called without result or error set."); @@ -65,12 +67,12 @@ public void handle(WarpSyncMachine sync) { } log.log(Level.INFO, "Successfully received fragments from peer " - + sync.getNetworkService().getCurrentSelectedPeer()); + + sync.getNetworkService().getCurrentSelectedPeer()); if (resp.getFragments().length == 0) { log.log(Level.WARNING, "No fragments received."); return; } - syncedState.setWarpSyncFragmentsFinished(resp.isFinished()); + warpSyncState.setWarpSyncFragmentsFinished(resp.isFinished()); sync.setFragmentsQueue(new LinkedBlockingQueue<>( Arrays.stream(resp.getFragments()).toList()) ); diff --git a/src/main/java/com/limechain/sync/warpsync/action/RuntimeBuildAction.java b/src/main/java/com/limechain/sync/warpsync/action/RuntimeBuildAction.java new file mode 100644 index 000000000..52b7d7673 --- /dev/null +++ b/src/main/java/com/limechain/sync/warpsync/action/RuntimeBuildAction.java @@ -0,0 +1,35 @@ +package com.limechain.sync.warpsync.action; + +import com.limechain.rpc.server.AppBean; +import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; +import lombok.AllArgsConstructor; +import lombok.extern.java.Log; + +import java.util.logging.Level; + +/** + * Creates a runtime instance using the downloaded code + */ +@Log +@AllArgsConstructor +public class RuntimeBuildAction implements WarpSyncAction { + + private final WarpSyncState warpSyncState; + + public RuntimeBuildAction() { + this(AppBean.getBean(WarpSyncState.class)); + } + + @Override + public void next(WarpSyncMachine sync) { + log.log(Level.INFO, "Done with runtime build"); + //After runtime instance is built, we are building the information of the chain + sync.setWarpSyncAction(new ChainInformationBuildAction()); + } + + @Override + public void handle(WarpSyncMachine sync) { + warpSyncState.buildRuntime(); + } +} diff --git a/src/main/java/com/limechain/sync/warpsync/state/RuntimeDownloadState.java b/src/main/java/com/limechain/sync/warpsync/action/RuntimeDownloadAction.java similarity index 58% rename from src/main/java/com/limechain/sync/warpsync/state/RuntimeDownloadState.java rename to src/main/java/com/limechain/sync/warpsync/action/RuntimeDownloadAction.java index 0e9bb3a1d..31640143e 100644 --- a/src/main/java/com/limechain/sync/warpsync/state/RuntimeDownloadState.java +++ b/src/main/java/com/limechain/sync/warpsync/action/RuntimeDownloadAction.java @@ -1,8 +1,10 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; -import com.limechain.sync.warpsync.SyncedState; -import com.limechain.sync.warpsync.WarpSyncMachine; import com.limechain.exception.global.RuntimeCodeException; +import com.limechain.rpc.server.AppBean; +import com.limechain.storage.block.SyncState; +import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import lombok.AllArgsConstructor; import lombok.extern.java.Log; @@ -10,30 +12,32 @@ @Log @AllArgsConstructor -public class RuntimeDownloadState implements WarpSyncState { - private final SyncedState syncedState; +public class RuntimeDownloadAction implements WarpSyncAction { + private final WarpSyncState warpSyncState; + private final SyncState syncState; private Exception error; - public RuntimeDownloadState() { - this.syncedState = SyncedState.getInstance(); + public RuntimeDownloadAction() { + this.warpSyncState = AppBean.getBean(WarpSyncState.class); + this.syncState = AppBean.getBean(SyncState.class); } @Override public void next(WarpSyncMachine sync) { if (this.error != null) { log.log(Level.SEVERE, "Error occurred during runtime download state: " + this.error.getMessage()); - sync.setWarpSyncState(new RequestFragmentsState(syncedState.getLastFinalizedBlockHash())); + sync.setWarpSyncAction(new RequestFragmentsAction(syncState.getLastFinalizedBlockHash())); return; } // After runtime is downloaded, we have to build the runtime and then build chain information - sync.setWarpSyncState(new RuntimeBuildState()); + sync.setWarpSyncAction(new RuntimeBuildAction()); } @Override public void handle(WarpSyncMachine sync) { try { log.log(Level.INFO, "Loading saved runtime..."); - syncedState.loadSavedRuntimeCode(); + warpSyncState.loadSavedRuntimeCode(); } catch (RuntimeCodeException e) { handleDownloadRuntime(); } @@ -42,7 +46,7 @@ public void handle(WarpSyncMachine sync) { private void handleDownloadRuntime() { try { log.log(Level.INFO, "Downloading runtime..."); - syncedState.updateRuntimeCode(); + warpSyncState.updateRuntimeCode(); } catch (RuntimeCodeException e) { this.error = e; } diff --git a/src/main/java/com/limechain/sync/warpsync/state/VerifyJustificationState.java b/src/main/java/com/limechain/sync/warpsync/action/VerifyJustificationAction.java similarity index 61% rename from src/main/java/com/limechain/sync/warpsync/state/VerifyJustificationState.java rename to src/main/java/com/limechain/sync/warpsync/action/VerifyJustificationAction.java index 565bb129c..a8e8fc36d 100644 --- a/src/main/java/com/limechain/sync/warpsync/state/VerifyJustificationState.java +++ b/src/main/java/com/limechain/sync/warpsync/action/VerifyJustificationAction.java @@ -1,10 +1,12 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; import com.limechain.exception.sync.JustificationVerificationException; import com.limechain.network.protocol.warp.dto.WarpSyncFragment; +import com.limechain.rpc.server.AppBean; +import com.limechain.storage.block.SyncState; import com.limechain.sync.JustificationVerifier; -import com.limechain.sync.warpsync.SyncedState; import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import lombok.extern.java.Log; import java.util.logging.Level; @@ -12,31 +14,37 @@ // VerifyJustificationState is going to be instantiated a lot of times // Maybe we can make it a singleton in order to reduce performance overhead? @Log -public class VerifyJustificationState implements WarpSyncState { - private final SyncedState syncedState = SyncedState.getInstance(); +public class VerifyJustificationAction implements WarpSyncAction { + private final WarpSyncState warpSyncState; + private final SyncState syncState; private Exception error; + public VerifyJustificationAction() { + this.syncState = AppBean.getBean(SyncState.class); + this.warpSyncState = AppBean.getBean(WarpSyncState.class); + } + @Override public void next(WarpSyncMachine sync) { if (this.error != null) { // Not sure what state we should transition to here. - sync.setWarpSyncState(new FinishedState()); + sync.setWarpSyncAction(new FinishedAction()); return; } if (!sync.getFragmentsQueue().isEmpty()) { - sync.setWarpSyncState(new VerifyJustificationState()); - } else if (syncedState.isWarpSyncFragmentsFinished()) { - sync.setWarpSyncState(new RuntimeDownloadState()); + sync.setWarpSyncAction(new VerifyJustificationAction()); + } else if (warpSyncState.isWarpSyncFragmentsFinished()) { + sync.setWarpSyncAction(new RuntimeDownloadAction()); } else { - sync.setWarpSyncState(new RequestFragmentsState(syncedState.getLastFinalizedBlockHash())); + sync.setWarpSyncAction(new RequestFragmentsAction(syncState.getLastFinalizedBlockHash())); } } @Override public void handle(WarpSyncMachine sync) { try { - syncedState.handleScheduledEvents(); + warpSyncState.handleScheduledEvents(); WarpSyncFragment fragment = sync.getFragmentsQueue().poll(); log.log(Level.INFO, "Verifying justification..."); @@ -50,11 +58,7 @@ public void handle(WarpSyncMachine sync) { throw new JustificationVerificationException("Justification could not be verified."); } - // Set the latest finalized header and number - // TODO: Persist header to DB? - syncedState.setStateRoot(fragment.getHeader().getStateRoot()); - syncedState.setLastFinalizedBlockHash(fragment.getJustification().getTargetHash()); - syncedState.setLastFinalizedBlockNumber(fragment.getJustification().getTargetBlock()); + syncState.finalizeHeader(fragment.getHeader()); handleAuthorityChanges(fragment); } catch (Exception e) { log.log(Level.WARNING, "Error while verifying justification: " + e.getMessage()); @@ -64,13 +68,13 @@ public void handle(WarpSyncMachine sync) { private void handleAuthorityChanges(WarpSyncFragment fragment) { try { - syncedState.handleAuthorityChanges( + warpSyncState.handleAuthorityChanges( fragment.getHeader().getDigest(), fragment.getJustification().getTargetBlock()); log.log(Level.INFO, "Verified justification. Block hash is now at #" - + syncedState.getLastFinalizedBlockNumber() + ": " - + syncedState.getLastFinalizedBlockHash().toString() - + " with state root " + syncedState.getStateRoot()); + + syncState.getLastFinalizedBlockNumber() + ": " + + syncState.getLastFinalizedBlockHash().toString() + + " with state root " + syncState.getStateRoot()); } catch (Exception e) { this.error = e; } diff --git a/src/main/java/com/limechain/sync/warpsync/state/WarpSyncState.java b/src/main/java/com/limechain/sync/warpsync/action/WarpSyncAction.java similarity index 63% rename from src/main/java/com/limechain/sync/warpsync/state/WarpSyncState.java rename to src/main/java/com/limechain/sync/warpsync/action/WarpSyncAction.java index 92bf38fe1..7676e4881 100644 --- a/src/main/java/com/limechain/sync/warpsync/state/WarpSyncState.java +++ b/src/main/java/com/limechain/sync/warpsync/action/WarpSyncAction.java @@ -1,8 +1,8 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; import com.limechain.sync.warpsync.WarpSyncMachine; -public interface WarpSyncState { +public interface WarpSyncAction { void next(WarpSyncMachine sync); void handle(WarpSyncMachine sync); diff --git a/src/main/java/com/limechain/sync/warpsync/dto/StateDto.java b/src/main/java/com/limechain/sync/warpsync/dto/StateDto.java deleted file mode 100644 index 752747cab..000000000 --- a/src/main/java/com/limechain/sync/warpsync/dto/StateDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.limechain.sync.warpsync.dto; - -import org.javatuples.Pair; - -import java.io.Serializable; -import java.math.BigInteger; -import java.util.List; - -public record StateDto(BigInteger latestRound, String lastFinalizedBlockHash, BigInteger lastFinalizedBlockNumber, - List> authoritySet, BigInteger setId) - implements Serializable { -} diff --git a/src/main/java/com/limechain/sync/warpsync/state/RuntimeBuildState.java b/src/main/java/com/limechain/sync/warpsync/state/RuntimeBuildState.java deleted file mode 100644 index 6de136590..000000000 --- a/src/main/java/com/limechain/sync/warpsync/state/RuntimeBuildState.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.limechain.sync.warpsync.state; - -import com.limechain.sync.warpsync.SyncedState; -import com.limechain.sync.warpsync.WarpSyncMachine; -import lombok.AllArgsConstructor; -import lombok.extern.java.Log; - -import java.util.logging.Level; - -/** - Creates a runtime instance using the downloaded code - */ -@Log -@AllArgsConstructor -public class RuntimeBuildState implements WarpSyncState { - private final SyncedState syncedState; - - public RuntimeBuildState() { - this.syncedState = SyncedState.getInstance(); - } - - @Override - public void next(WarpSyncMachine sync) { - log.log(Level.INFO, "Done with runtime build"); - //After runtime instance is built, we are building the information of the chain - sync.setWarpSyncState(new ChainInformationBuildState()); - } - - @Override - public void handle(WarpSyncMachine sync) { - syncedState.buildRuntime(syncedState.getLastFinalizedBlockHash()); - } -} diff --git a/src/test/java/com/limechain/config/SystemInfoTest.java b/src/test/java/com/limechain/config/SystemInfoTest.java index b504182fe..00f98c88b 100644 --- a/src/test/java/com/limechain/config/SystemInfoTest.java +++ b/src/test/java/com/limechain/config/SystemInfoTest.java @@ -3,10 +3,13 @@ import com.limechain.chain.Chain; import com.limechain.network.Network; import com.limechain.network.protocol.blockannounce.NodeRole; +import com.limechain.storage.block.SyncState; import io.libp2p.core.Host; import io.libp2p.core.PeerId; import org.junit.jupiter.api.Test; +import java.math.BigInteger; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -25,15 +28,20 @@ void SystemInfo_SetsRole_NoCliOption() { when(network.getHost()).thenReturn(host); when(network.getNodeRole()).thenReturn(NodeRole.FULL); - SystemInfo systemInfo = new SystemInfo(hostConfig, network); + SyncState syncState = mock(SyncState.class); + when(syncState.getLastFinalizedBlockNumber()).thenReturn(BigInteger.ZERO); + + SystemInfo systemInfo = new SystemInfo(hostConfig, network, syncState); String expectedRole = NodeRole.FULL.name(); Chain expectedChain = Chain.POLKADOT; String expectedDbPath = "./test/db"; String expectedHostIdentity = "12D3KooWRHfNJwkKeSJWD28hYFyA18dcN9qU1JEzJJaguarDPS"; + BigInteger expectedHighestBlock = BigInteger.ZERO; assertEquals(expectedRole, systemInfo.getRole()); assertEquals(expectedChain, systemInfo.getChain()); assertEquals(expectedDbPath, systemInfo.getDbPath()); assertEquals(expectedHostIdentity, systemInfo.getHostIdentity()); + assertEquals(expectedHighestBlock, systemInfo.getHighestBlock()); } } diff --git a/src/test/java/com/limechain/network/ConnectionManagerTest.java b/src/test/java/com/limechain/network/ConnectionManagerTest.java index 822756e6b..f3da25e9b 100644 --- a/src/test/java/com/limechain/network/ConnectionManagerTest.java +++ b/src/test/java/com/limechain/network/ConnectionManagerTest.java @@ -3,7 +3,7 @@ import com.limechain.network.dto.PeerInfo; import com.limechain.network.dto.ProtocolStreamType; import com.limechain.network.dto.ProtocolStreams; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessage; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceMessage; import com.limechain.network.protocol.warp.dto.BlockHeader; import io.emeraldpay.polkaj.types.Hash256; import io.libp2p.core.PeerId; diff --git a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceControllerTest.java b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceControllerTest.java index bbee061d5..887e8aae8 100644 --- a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceControllerTest.java +++ b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceControllerTest.java @@ -1,5 +1,7 @@ package com.limechain.network.protocol.blockannounce; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshakeBuilder; import io.libp2p.core.PeerId; import io.libp2p.core.Stream; import org.junit.jupiter.api.BeforeEach; @@ -7,6 +9,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.Mockito.verify; @@ -22,10 +25,13 @@ class BlockAnnounceControllerTest { private PeerId peerId; @Mock private BlockAnnounceEngine engine; + @Mock + private BlockAnnounceHandshakeBuilder blockAnnounceHandshakeBuilder; @BeforeEach void setup() { blockAnnounceController.engine = engine; + engine.handshakeBuilder = blockAnnounceHandshakeBuilder; } @Test diff --git a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngineTest.java b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngineTest.java index d9ad0436a..b1c8d5e59 100644 --- a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngineTest.java +++ b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceEngineTest.java @@ -1,12 +1,13 @@ package com.limechain.network.protocol.blockannounce; import com.limechain.network.ConnectionManager; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshakeBuilder; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceMessage; import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshakeScaleWriter; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessage; import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessageScaleReader; import com.limechain.network.protocol.warp.dto.BlockHeader; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.sync.warpsync.WarpSyncState; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleCodecWriter; import io.libp2p.core.PeerId; @@ -45,10 +46,12 @@ class BlockAnnounceEngineTest { private ConnectionManager connectionManager; @Mock - private SyncedState syncedState; + private WarpSyncState warpSyncState; @Mock private BlockAnnounceHandshake handshake; + @Mock + private BlockAnnounceHandshakeBuilder handshakeBuilder; @Test void receiveNonHandshakeRequestWhenNotConnectedShouldIgnore() { @@ -59,7 +62,7 @@ void receiveNonHandshakeRequestWhenNotConnectedShouldIgnore() { blockAnnounceEngine.receiveRequest(message, stream); verifyNoMoreInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); } @Test @@ -68,7 +71,7 @@ void receiveHandshakeRequestWhenNotConnectedShouldAddStreamToConnection() { Arrays.fill(message, (byte) 1); when(stream.remotePeerId()).thenReturn(peerId); when(connectionManager.isBlockAnnounceConnected(peerId)).thenReturn(false); - when(syncedState.getHandshake()).thenReturn(handshake); + when(handshakeBuilder.getBlockAnnounceHandshake()).thenReturn(handshake); try ( MockedConstruction readerMock = mockConstruction(ScaleCodecReader.class, (mock, context) -> when(mock.read(any())).thenReturn(handshake)); @@ -86,7 +89,7 @@ void receiveHandshakeRequestWhenNotConnectedShouldSendHandshakeBack() throws IOE Arrays.fill(message, (byte) 1); when(stream.remotePeerId()).thenReturn(peerId); when(connectionManager.isBlockAnnounceConnected(peerId)).thenReturn(false); - when(syncedState.getHandshake()).thenReturn(handshake); + when(handshakeBuilder.getBlockAnnounceHandshake()).thenReturn(handshake); try ( MockedConstruction readerMock = mockConstruction(ScaleCodecReader.class); MockedConstruction writerMock = mockConstruction(ScaleCodecWriter.class) @@ -144,7 +147,7 @@ void receiveBlockAnnounceWhenConnectedShouldSyncMessage() { ) { blockAnnounceEngine.receiveRequest(message, stream); - verify(syncedState).syncBlockAnnounce(blockAnnounceMessage); + verify(warpSyncState).syncBlockAnnounce(blockAnnounceMessage); } } } \ No newline at end of file diff --git a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceProtocolTest.java b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceProtocolTest.java index fe89ea4c5..af4eec202 100644 --- a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceProtocolTest.java +++ b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceProtocolTest.java @@ -3,6 +3,7 @@ import com.limechain.network.ConnectionManager; import com.limechain.network.encoding.Leb128LengthFrameDecoder; import com.limechain.network.encoding.Leb128LengthFrameEncoder; +import com.limechain.rpc.server.AppBean; import io.libp2p.core.Stream; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -11,6 +12,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -33,26 +36,32 @@ class BlockAnnounceProtocolTest { @Test void onStartInitiator() { - BlockAnnounceController result = blockAnnounceProtocol.onStartInitiator(stream).join(); + try (MockedStatic appBean = Mockito.mockStatic(AppBean.class)) { + appBean.when(() -> AppBean.getBean(BlockAnnounceEngine.class)).thenReturn(blockAnnounceEngine); + BlockAnnounceController result = blockAnnounceProtocol.onStartInitiator(stream).join(); - verify(stream).pushHandler(any(Leb128LengthFrameEncoder.class)); - verify(stream).pushHandler(any(Leb128LengthFrameDecoder.class)); - verify(stream).pushHandler(any(ByteArrayEncoder.class)); - verify(stream).pushHandler(any(BlockAnnounceProtocol.NotificationHandler.class)); + verify(stream).pushHandler(any(Leb128LengthFrameEncoder.class)); + verify(stream).pushHandler(any(Leb128LengthFrameDecoder.class)); + verify(stream).pushHandler(any(ByteArrayEncoder.class)); + verify(stream).pushHandler(any(BlockAnnounceProtocol.NotificationHandler.class)); - assertEquals(stream, result.stream); + assertEquals(stream, result.stream); + } } @Test void onStartResponder() { - BlockAnnounceController result = blockAnnounceProtocol.onStartResponder(stream).join(); + try (MockedStatic appBean = Mockito.mockStatic(AppBean.class)) { + appBean.when(() -> AppBean.getBean(BlockAnnounceEngine.class)).thenReturn(blockAnnounceEngine); + BlockAnnounceController result = blockAnnounceProtocol.onStartResponder(stream).join(); - verify(stream).pushHandler(any(Leb128LengthFrameEncoder.class)); - verify(stream).pushHandler(any(Leb128LengthFrameDecoder.class)); - verify(stream).pushHandler(any(ByteArrayEncoder.class)); - verify(stream).pushHandler(any(BlockAnnounceProtocol.NotificationHandler.class)); + verify(stream).pushHandler(any(Leb128LengthFrameEncoder.class)); + verify(stream).pushHandler(any(Leb128LengthFrameDecoder.class)); + verify(stream).pushHandler(any(ByteArrayEncoder.class)); + verify(stream).pushHandler(any(BlockAnnounceProtocol.NotificationHandler.class)); - assertEquals(stream, result.stream); + assertEquals(stream, result.stream); + } } @Test diff --git a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceServiceTest.java b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceServiceTest.java index bbabebd2c..cfc5ff562 100644 --- a/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceServiceTest.java +++ b/src/test/java/com/limechain/network/protocol/blockannounce/BlockAnnounceServiceTest.java @@ -1,7 +1,7 @@ package com.limechain.network.protocol.blockannounce; import com.limechain.network.kad.KademliaService; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; import com.limechain.utils.RandomGenerationUtils; import io.emeraldpay.polkaj.types.Hash256; import io.ipfs.multiaddr.MultiAddress; diff --git a/src/test/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReaderTest.java b/src/test/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReaderTest.java index 173782d8b..6ce42240c 100644 --- a/src/test/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReaderTest.java +++ b/src/test/java/com/limechain/network/protocol/blockannounce/scale/BlockAnnounceHandshakeScaleReaderTest.java @@ -1,6 +1,7 @@ package com.limechain.network.protocol.blockannounce.scale; import com.google.protobuf.ByteString; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.scale.ScaleCodecWriter; import io.emeraldpay.polkaj.types.Hash256; diff --git a/src/test/java/com/limechain/network/protocol/grandpa/GrandpaEngineTest.java b/src/test/java/com/limechain/network/protocol/grandpa/GrandpaEngineTest.java index 30ec02fdf..0b5fbcdff 100644 --- a/src/test/java/com/limechain/network/protocol/grandpa/GrandpaEngineTest.java +++ b/src/test/java/com/limechain/network/protocol/grandpa/GrandpaEngineTest.java @@ -3,7 +3,8 @@ import com.limechain.network.ConnectionManager; import com.limechain.network.dto.PeerInfo; import com.limechain.network.protocol.blockannounce.NodeRole; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshake; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceHandshakeBuilder; import com.limechain.network.protocol.grandpa.messages.catchup.req.CatchUpReqMessage; import com.limechain.network.protocol.grandpa.messages.catchup.req.CatchUpReqMessageScaleReader; import com.limechain.network.protocol.grandpa.messages.catchup.res.CatchUpMessage; @@ -11,10 +12,11 @@ import com.limechain.network.protocol.grandpa.messages.commit.CommitMessage; import com.limechain.network.protocol.grandpa.messages.commit.CommitMessageScaleReader; import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessage; +import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessageBuilder; import com.limechain.network.protocol.grandpa.messages.neighbour.NeighbourMessageScaleReader; import com.limechain.network.protocol.grandpa.messages.vote.VoteMessage; import com.limechain.network.protocol.grandpa.messages.vote.VoteMessageScaleReader; -import com.limechain.sync.warpsync.SyncedState; +import com.limechain.sync.warpsync.WarpSyncState; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.libp2p.core.PeerId; import io.libp2p.core.Stream; @@ -48,7 +50,11 @@ class GrandpaEngineTest { @Mock private ConnectionManager connectionManager; @Mock - private SyncedState syncedState; + private WarpSyncState warpSyncState; + @Mock + private NeighbourMessageBuilder neighbourMessageBuilder; + @Mock + private BlockAnnounceHandshakeBuilder blockAnnounceHandshakeBuilder; private final NeighbourMessage neighbourMessage = new NeighbourMessage(1, BigInteger.ONE, BigInteger.TWO, BigInteger.TEN); @@ -62,7 +68,7 @@ void receiveRequestWithUnknownGrandpaTypeShouldLogAndIgnore() { grandpaEngine.receiveRequest(unknownTypeMessage, stream); verifyNoInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); } // INITIATOR STREAM @@ -76,7 +82,7 @@ void receiveNonHandshakeRequestOnInitiatorStreamShouldLogAndIgnore() { grandpaEngine.receiveRequest(message, stream); verifyNoInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); } @Test @@ -84,7 +90,7 @@ void receiveHandshakeOnInitiatorStreamShouldAddStreamToConnection() { byte[] message = new byte[] { 2 }; when(stream.isInitiator()).thenReturn(true); when(stream.remotePeerId()).thenReturn(peerId); - when(syncedState.getNeighbourMessage()).thenReturn(neighbourMessage); + when(neighbourMessageBuilder.getNeighbourMessage()).thenReturn(neighbourMessage); grandpaEngine.receiveRequest(message, stream); @@ -94,7 +100,7 @@ void receiveHandshakeOnInitiatorStreamShouldAddStreamToConnection() { @Test void receiveHandshakeOnInitiatorStreamShouldSendNeighbourMessageBack() { byte[] message = new byte[] { 2 }; - when(syncedState.getNeighbourMessage()).thenReturn(neighbourMessage); + when(neighbourMessageBuilder.getNeighbourMessage()).thenReturn(neighbourMessage); when(stream.isInitiator()).thenReturn(true); grandpaEngine.receiveRequest(message, stream); @@ -112,7 +118,7 @@ void receiveNonHandshakeRequestOnResponderStreamWhenNotConnectedShouldLogAndClos grandpaEngine.receiveRequest(message, stream); verifyNoMoreInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); verify(stream).close(); } @@ -126,7 +132,7 @@ void receiveHandshakeRequestOnResponderStreamWhenAlreadyConnectedShouldLogAndClo grandpaEngine.receiveRequest(message, stream); verifyNoMoreInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); verify(stream).close(); } @@ -137,7 +143,7 @@ void receiveHandshakeRequestOnResponderStreamWhenNotConnectedShouldAddStreamToCo when(stream.remotePeerId()).thenReturn(peerId); when(connectionManager.isGrandpaConnected(peerId)).thenReturn(false); when(connectionManager.getPeerInfo(peerId)).thenReturn(mock(PeerInfo.class)); - when(syncedState.getHandshake()).thenReturn(mock(BlockAnnounceHandshake.class)); + when(blockAnnounceHandshakeBuilder.getBlockAnnounceHandshake()).thenReturn(mock(BlockAnnounceHandshake.class)); grandpaEngine.receiveRequest(message, stream); @@ -154,7 +160,7 @@ void receiveHandshakeRequestOnResponderStreamWhenNotConnectedShouldSendHandshake when(connectionManager.isGrandpaConnected(peerId)).thenReturn(false); when(connectionManager.getPeerInfo(peerId)).thenReturn(mock(PeerInfo.class)); BlockAnnounceHandshake handshake = mock(BlockAnnounceHandshake.class); - when(syncedState.getHandshake()).thenReturn(handshake); + when(blockAnnounceHandshakeBuilder.getBlockAnnounceHandshake()).thenReturn(handshake); when(handshake.getNodeRole()).thenReturn(role); grandpaEngine.receiveRequest(message, stream); @@ -176,7 +182,7 @@ void receiveCommitMessageOnResponderStreamWhenShouldSyncCommit() { ) { grandpaEngine.receiveRequest(message, stream); - verify(syncedState).syncCommit(commitMessage, peerId); + verify(warpSyncState).syncCommit(commitMessage, peerId); } } @@ -194,7 +200,7 @@ void receiveNeighbourMessageOnResponderStreamWhenShouldSyncNeighbourMessage() { (mock, context) -> when(mock.read(any(NeighbourMessageScaleReader.class))).thenReturn(neighbourMessage)) ) { grandpaEngine.receiveRequest(message, stream); - verify(syncedState).syncNeighbourMessage(neighbourMessage, peerId); + verify(warpSyncState).syncNeighbourMessage(neighbourMessage, peerId); } } @@ -213,7 +219,7 @@ void receiveVoteMessageOnResponderStreamShouldDecodeLogAndIgnore() { grandpaEngine.receiveRequest(message, stream); verifyNoMoreInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); } } @@ -232,7 +238,7 @@ void receiveCatchUpRequestMessageOnResponderStreamShouldLogAndIgnore() { grandpaEngine.receiveRequest(message, stream); verifyNoMoreInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); } } @@ -251,7 +257,7 @@ void receiveCatchUpResponseMessageOnResponderStreamShouldLogAndIgnore() { grandpaEngine.receiveRequest(message, stream); verifyNoMoreInteractions(connectionManager); - verifyNoInteractions(syncedState); + verifyNoInteractions(warpSyncState); } } @@ -260,7 +266,7 @@ void receiveCatchUpResponseMessageOnResponderStreamShouldLogAndIgnore() { void writeHandshakeToStream() { Integer role = NodeRole.LIGHT.getValue(); BlockAnnounceHandshake handshake = mock(BlockAnnounceHandshake.class); - when(syncedState.getHandshake()).thenReturn(handshake); + when(blockAnnounceHandshakeBuilder.getBlockAnnounceHandshake()).thenReturn(handshake); when(handshake.getNodeRole()).thenReturn(role); grandpaEngine.writeHandshakeToStream(stream, peerId); @@ -270,7 +276,7 @@ void writeHandshakeToStream() { @Test void writeNeighbourMessage() { - when(syncedState.getNeighbourMessage()).thenReturn(neighbourMessage); + when(neighbourMessageBuilder.getNeighbourMessage()).thenReturn(neighbourMessage); grandpaEngine.writeNeighbourMessage(stream, peerId); diff --git a/src/test/java/com/limechain/rpc/methods/system/SystemRPCImplTest.java b/src/test/java/com/limechain/rpc/methods/system/SystemRPCImplTest.java index eb76c4557..07f28696a 100644 --- a/src/test/java/com/limechain/rpc/methods/system/SystemRPCImplTest.java +++ b/src/test/java/com/limechain/rpc/methods/system/SystemRPCImplTest.java @@ -5,6 +5,8 @@ import com.limechain.chain.spec.ChainType; import com.limechain.config.SystemInfo; import com.limechain.network.Network; +import com.limechain.network.protocol.blockannounce.NodeRole; +import com.limechain.storage.block.SyncState; import com.limechain.sync.warpsync.WarpSyncMachine; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -23,6 +25,7 @@ class SystemRPCImplTest { private WarpSyncMachine warpSync; private Network network; private SystemInfo systemInfo; + private SyncState syncState; @BeforeEach public void setup() { @@ -30,7 +33,8 @@ public void setup() { systemInfo = mock(SystemInfo.class); warpSync = mock(WarpSyncMachine.class); network = mock(Network.class); - systemRPC = new SystemRPCImpl(chainService, systemInfo, network, warpSync); + syncState = mock(SyncState.class); + systemRPC = new SystemRPCImpl(chainService, systemInfo, network, warpSync, syncState); } @Test @@ -49,9 +53,9 @@ void systemVersion() { @Test void systemNodeRoles() { - when(systemInfo.getRole()).thenReturn("Light Client"); + when(systemInfo.getRole()).thenReturn(NodeRole.LIGHT.name()); - assertArrayEquals(new String[]{"Light Client"}, systemRPC.systemNodeRoles()); + assertArrayEquals(new String[]{"LIGHT"}, systemRPC.systemNodeRoles()); } @Test diff --git a/src/test/java/com/limechain/sync/warpsync/SyncedStateTest.java b/src/test/java/com/limechain/sync/warpsync/WarpSyncActionTest.java similarity index 63% rename from src/test/java/com/limechain/sync/warpsync/SyncedStateTest.java rename to src/test/java/com/limechain/sync/warpsync/WarpSyncActionTest.java index f85114186..5d22b995b 100644 --- a/src/test/java/com/limechain/sync/warpsync/SyncedStateTest.java +++ b/src/test/java/com/limechain/sync/warpsync/WarpSyncActionTest.java @@ -3,7 +3,7 @@ import com.google.protobuf.ByteString; import com.limechain.exception.global.RuntimeCodeException; import com.limechain.network.Network; -import com.limechain.network.protocol.blockannounce.scale.BlockAnnounceMessage; +import com.limechain.network.protocol.blockannounce.messages.BlockAnnounceMessage; import com.limechain.network.protocol.lightclient.pb.LightClientMessage; import com.limechain.network.protocol.warp.dto.BlockHeader; import com.limechain.network.protocol.warp.dto.DigestType; @@ -12,6 +12,9 @@ import com.limechain.runtime.RuntimeBuilder; import com.limechain.storage.DBConstants; import com.limechain.storage.KVRepository; +import com.limechain.storage.block.SyncState; +import com.limechain.trie.decoded.Trie; +import com.limechain.trie.decoded.TrieVerifier; import io.emeraldpay.polkaj.scale.ScaleCodecReader; import io.emeraldpay.polkaj.types.Hash256; import org.junit.jupiter.api.Test; @@ -20,6 +23,7 @@ import org.mockito.Mock; import org.mockito.MockedConstruction; import org.mockito.MockedStatic; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import java.math.BigInteger; @@ -28,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; @@ -37,54 +42,60 @@ @SuppressWarnings("unused") @ExtendWith(MockitoExtension.class) -class SyncedStateTest { +class WarpSyncActionTest { @InjectMocks - private SyncedState syncedState; - + @Spy + private WarpSyncState warpSyncState; @Mock private Set scheduledRuntimeUpdateBlocks; @Mock - private Hash256 lastFinalizedBlockHash; - @Mock - private Hash256 stateRoot; + private SyncState syncState; @Mock private RuntimeBuilder runtimeBuilder; @Mock private KVRepository repository; @Mock private Network network; + @Mock + private Hash256 lastFinalizedBlockHash; + @Mock + private Hash256 stateRoot; + @Mock + private Trie mockTrie; @Test void updateRuntimeCode() throws RuntimeCodeException { - LightClientMessage.Response response = mock(LightClientMessage.Response.class); + LightClientMessage.Response response = mock(LightClientMessage.Response.class); LightClientMessage.RemoteReadResponse remoteReadResponse = mock(LightClientMessage.RemoteReadResponse.class); ByteString wrappedProof = mock(ByteString.class); - byte[] proof = new byte[] { 1, 2, 3 }; - byte[] decodedProof = new byte[] { 4, 5, 6 }; - byte[][] decodedProofs = new byte[][] { decodedProof }; + byte[] proof = new byte[]{1, 2, 3}; + byte[] decodedProof = new byte[]{4, 5, 6}; + byte[][] decodedProofs = new byte[][]{decodedProof}; String blockHashString = "blhash"; - String[] codeKey = new String[]{ SyncedState.CODE_KEY }; + String[] codeKey = new String[]{WarpSyncState.CODE_KEY}; String stateRootString = "state root"; - byte[] runtimeCode = new byte[]{ 1, 2 }; + byte[] runtimeCode = new byte[]{1, 2}; + when(syncState.getLastFinalizedBlockHash()).thenReturn(lastFinalizedBlockHash); when(lastFinalizedBlockHash.toString()).thenReturn(blockHashString); - when(stateRoot.toString()).thenReturn(stateRootString); + when(syncState.getStateRoot()).thenReturn(stateRoot); when(network.makeRemoteReadRequest(blockHashString, codeKey)).thenReturn(response); when(response.getRemoteReadResponse()).thenReturn(remoteReadResponse); when(remoteReadResponse.getProof()).thenReturn(wrappedProof); when(wrappedProof.toByteArray()).thenReturn(proof); - when(runtimeBuilder.buildRuntimeCode(decodedProofs, stateRoot)).thenReturn(runtimeCode); try (MockedConstruction readerMock = mockConstruction((ScaleCodecReader.class), (mock, context) -> { when(mock.readCompactInt()).thenReturn(1); when(mock.readByteArray()).thenReturn(decodedProof); - }) + }); MockedStatic staticVerifier = mockStatic(TrieVerifier.class) ) { - syncedState.updateRuntimeCode(); + staticVerifier.when(() -> TrieVerifier.buildTrie(decodedProofs, stateRoot.getBytes())).thenReturn(mockTrie); + when(mockTrie.get(any())).thenReturn(runtimeCode); - verify(repository).save(DBConstants.STATE_TRIE_MERKLE_PROOF, decodedProofs); - verify(repository).save(DBConstants.STATE_TRIE_ROOT_HASH, stateRootString); - assertEquals(runtimeCode, syncedState.getRuntimeCode()); + warpSyncState.updateRuntimeCode(); + + verify(repository).save(DBConstants.RUNTIME_CODE, runtimeCode); + assertEquals(runtimeCode, warpSyncState.getRuntimeCode()); } } @@ -99,7 +110,7 @@ void syncBlockAnnounceWhenHasRunEnvUpdatedDigestShouldScheduleRuntimeUpdate() { when(headerDigest.getType()).thenReturn(DigestType.RUN_ENV_UPDATED); when(blockHeader.getBlockNumber()).thenReturn(blockNumber); - syncedState.syncBlockAnnounce(blockAnnounceMessage); + warpSyncState.syncBlockAnnounce(blockAnnounceMessage); verify(scheduledRuntimeUpdateBlocks).add(blockNumber); } @@ -113,61 +124,48 @@ void syncBlockAnnounceWhenNoRunEnvUpdatedDigestShouldDoNothing() { when(blockHeader.getDigest()).thenReturn(new HeaderDigest[]{headerDigest}); when(headerDigest.getType()).thenReturn(DigestType.OTHER); - syncedState.syncBlockAnnounce(blockAnnounceMessage); + warpSyncState.syncBlockAnnounce(blockAnnounceMessage); verifyNoInteractions(scheduledRuntimeUpdateBlocks); } @Test void loadSavedRuntimeWhenValuesAvailableShouldBuildRuntimeCode() throws RuntimeCodeException { - byte[][] merkleProof = new byte[][] {{1, 2}, {3, 4}}; + byte[][] merkleProof = new byte[][]{{1, 2}, {3, 4}}; Object stateRootObject = mock(Object.class); - String stateRoot = "root"; + String stateRootStr = "root"; Hash256 stateRootHash = mock(Hash256.class); - byte[] runtimeCode = new byte[]{ 1, 2 }; - when(repository.find(DBConstants.STATE_TRIE_MERKLE_PROOF)).thenReturn(Optional.of(merkleProof)); - when(repository.find(DBConstants.STATE_TRIE_ROOT_HASH)).thenReturn(Optional.of(stateRootObject)); - when(stateRootObject.toString()).thenReturn(stateRoot); - when(runtimeBuilder.buildRuntimeCode(merkleProof, stateRootHash)).thenReturn(runtimeCode); + byte[] runtimeCode = new byte[]{1, 2}; + when(repository.find(DBConstants.RUNTIME_CODE)).thenReturn(Optional.of(runtimeCode)); - try (MockedStatic hashMock = mockStatic(Hash256.class)) { - hashMock.when(() -> Hash256.from(stateRoot)).thenReturn(stateRootHash); + try (MockedStatic hashMock = mockStatic(Hash256.class); + MockedStatic staticVerifier = mockStatic(TrieVerifier.class)) { + hashMock.when(() -> Hash256.from(stateRootStr)).thenReturn(stateRootHash); - syncedState.loadSavedRuntimeCode(); + warpSyncState.loadSavedRuntimeCode(); - assertEquals(runtimeCode, syncedState.getRuntimeCode()); + assertEquals(runtimeCode, warpSyncState.getRuntimeCode()); } } @Test - void loadSavedRuntimeWhenMissingMerkleProofShouldThrow() { - when(repository.find(DBConstants.STATE_TRIE_MERKLE_PROOF)).thenReturn(Optional.empty()); - - assertThrows(RuntimeCodeException.class, - () -> syncedState.loadSavedRuntimeCode(), - "No available merkle proof"); - } - - @Test - void loadSavedRuntimeWhenMissingStateHashProofShouldThrow() { - byte[][] merkleProof = new byte[][]{{1, 2}, {3, 4}}; - when(repository.find(DBConstants.STATE_TRIE_MERKLE_PROOF)).thenReturn(Optional.of(merkleProof)); - when(repository.find(DBConstants.STATE_TRIE_ROOT_HASH)).thenReturn(Optional.empty()); + void loadSavedRuntimeWhenMissingRuntimeCodeShouldThrow() { + when(repository.find(DBConstants.RUNTIME_CODE)).thenReturn(Optional.empty()); assertThrows(RuntimeCodeException.class, - () -> syncedState.loadSavedRuntimeCode(), - "No available state root"); + () -> warpSyncState.loadSavedRuntimeCode(), + "No available runtime code"); } @Test void buildRuntime() { - byte[] runtimeCode = new byte[] { 1, 2, 3 }; - syncedState.setRuntimeCode(runtimeCode); + byte[] runtimeCode = new byte[]{1, 2, 3}; + warpSyncState.setRuntimeCode(runtimeCode); Runtime runtime = mock(Runtime.class); when(runtimeBuilder.buildRuntime(runtimeCode)).thenReturn(runtime); - syncedState.buildRuntime(mock(Hash256.class)); + warpSyncState.buildRuntime(); - assertEquals(runtime, syncedState.getRuntime()); + assertEquals(runtime, warpSyncState.getRuntime()); } } \ No newline at end of file diff --git a/src/test/java/com/limechain/sync/warpsync/state/RuntimeBuildStateTest.java b/src/test/java/com/limechain/sync/warpsync/action/RuntimeBuildStateTest.java similarity index 69% rename from src/test/java/com/limechain/sync/warpsync/state/RuntimeBuildStateTest.java rename to src/test/java/com/limechain/sync/warpsync/action/RuntimeBuildStateTest.java index 2c4f6c89f..ebe74adc8 100644 --- a/src/test/java/com/limechain/sync/warpsync/state/RuntimeBuildStateTest.java +++ b/src/test/java/com/limechain/sync/warpsync/action/RuntimeBuildStateTest.java @@ -1,7 +1,7 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; -import com.limechain.sync.warpsync.SyncedState; import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -14,9 +14,9 @@ @ExtendWith(MockitoExtension.class) class RuntimeBuildStateTest { @InjectMocks - private RuntimeBuildState runtimeBuildState; + private RuntimeBuildAction runtimeBuildState; @Mock - private SyncedState syncedState; + private WarpSyncState warpSyncState; @Mock private WarpSyncMachine warpSyncMachine; @@ -24,14 +24,14 @@ class RuntimeBuildStateTest { void nextSetsChainInformationBuildState() { runtimeBuildState.next(warpSyncMachine); - verify(warpSyncMachine).setWarpSyncState(any(ChainInformationBuildState.class)); + verify(warpSyncMachine).setWarpSyncAction(any(ChainInformationBuildAction.class)); } @Test void handleCallsSyncStateBuildRuntime() { runtimeBuildState.handle(warpSyncMachine); - verify(syncedState).buildRuntime(null); + verify(warpSyncState).buildRuntime(); } } \ No newline at end of file diff --git a/src/test/java/com/limechain/sync/warpsync/state/RuntimeDownloadStateTest.java b/src/test/java/com/limechain/sync/warpsync/action/RuntimeDownloadStateTest.java similarity index 69% rename from src/test/java/com/limechain/sync/warpsync/state/RuntimeDownloadStateTest.java rename to src/test/java/com/limechain/sync/warpsync/action/RuntimeDownloadStateTest.java index c477f0f42..9cfdddd7a 100644 --- a/src/test/java/com/limechain/sync/warpsync/state/RuntimeDownloadStateTest.java +++ b/src/test/java/com/limechain/sync/warpsync/action/RuntimeDownloadStateTest.java @@ -1,8 +1,9 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; -import com.limechain.sync.warpsync.SyncedState; -import com.limechain.sync.warpsync.WarpSyncMachine; import com.limechain.exception.global.RuntimeCodeException; +import com.limechain.storage.block.SyncState; +import com.limechain.sync.warpsync.WarpSyncMachine; +import com.limechain.sync.warpsync.WarpSyncState; import io.emeraldpay.polkaj.types.Hash256; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,9 +27,11 @@ @ExtendWith(MockitoExtension.class) class RuntimeDownloadStateTest { @InjectMocks - private RuntimeDownloadState runtimeDownloadState; + private RuntimeDownloadAction runtimeDownloadState; + @Mock + private WarpSyncState warpSyncState; @Mock - private SyncedState syncedState; + private SyncState syncState; @Mock private WarpSyncMachine warpSyncMachine; @@ -38,25 +41,25 @@ void nextWhenNoErrorShouldSetRuntimeBuildState() { runtimeDownloadState.next(warpSyncMachine); - verify(warpSyncMachine).setWarpSyncState(any(RuntimeBuildState.class)); + verify(warpSyncMachine).setWarpSyncAction(any(RuntimeBuildAction.class)); } @Test void nextWhenErrorShouldSetRequestFragmentState() { ReflectionTestUtils.setField(runtimeDownloadState, "error", mock(Exception.class)); Hash256 blockHash = mock(Hash256.class); - when(syncedState.getLastFinalizedBlockHash()).thenReturn(blockHash); + when(syncState.getLastFinalizedBlockHash()).thenReturn(blockHash); List capturedArguments = new ArrayList<>(); - try (MockedConstruction stateMock = mockConstruction(RequestFragmentsState.class, + try (MockedConstruction stateMock = mockConstruction(RequestFragmentsAction.class, (mock, context) -> capturedArguments.add(context.arguments().get(0)))) { runtimeDownloadState.next(warpSyncMachine); assertEquals(blockHash, capturedArguments.get(0)); assertEquals(1, stateMock.constructed().size()); - RequestFragmentsState constructedState = stateMock.constructed().get(0); + RequestFragmentsAction constructedState = stateMock.constructed().get(0); - verify(warpSyncMachine).setWarpSyncState(constructedState); + verify(warpSyncMachine).setWarpSyncAction(constructedState); } } @@ -64,23 +67,23 @@ void nextWhenErrorShouldSetRequestFragmentState() { void handleShouldTryToLoadSavedRuntime() throws RuntimeCodeException { runtimeDownloadState.handle(warpSyncMachine); - verify(syncedState).loadSavedRuntimeCode(); + verify(warpSyncState).loadSavedRuntimeCode(); } @Test void handleWhenLoadFailsShouldTryToUpdateRuntime() throws RuntimeCodeException { - doThrow(mock(RuntimeCodeException.class)).when(syncedState).loadSavedRuntimeCode(); + doThrow(mock(RuntimeCodeException.class)).when(warpSyncState).loadSavedRuntimeCode(); runtimeDownloadState.handle(warpSyncMachine); - verify(syncedState).updateRuntimeCode(); + verify(warpSyncState).updateRuntimeCode(); } @Test void handleUpdateRuntimeFailsShouldUpdateErrorField() throws RuntimeCodeException { - doThrow(mock(RuntimeCodeException.class)).when(syncedState).loadSavedRuntimeCode(); + doThrow(mock(RuntimeCodeException.class)).when(warpSyncState).loadSavedRuntimeCode(); RuntimeCodeException updateRuntimeCodeException = mock(RuntimeCodeException.class); - doThrow(updateRuntimeCodeException).when(syncedState).updateRuntimeCode(); + doThrow(updateRuntimeCodeException).when(warpSyncState).updateRuntimeCode(); runtimeDownloadState.handle(warpSyncMachine); diff --git a/src/test/java/com/limechain/sync/warpsync/state/RuntimeDownloadTest.java b/src/test/java/com/limechain/sync/warpsync/action/RuntimeDownloadTest.java similarity index 99% rename from src/test/java/com/limechain/sync/warpsync/state/RuntimeDownloadTest.java rename to src/test/java/com/limechain/sync/warpsync/action/RuntimeDownloadTest.java index 2e627f6fd..f86a7c157 100644 --- a/src/test/java/com/limechain/sync/warpsync/state/RuntimeDownloadTest.java +++ b/src/test/java/com/limechain/sync/warpsync/action/RuntimeDownloadTest.java @@ -1,5 +1,6 @@ -package com.limechain.sync.warpsync.state; +package com.limechain.sync.warpsync.action; +import com.limechain.exception.trie.TrieDecoderException; import com.limechain.network.kad.KademliaService; import com.limechain.network.protocol.lightclient.LightMessages; import com.limechain.network.protocol.lightclient.LightMessagesProtocol; @@ -7,7 +8,6 @@ import com.limechain.runtime.RuntimeBuilder; import com.limechain.trie.decoded.Trie; import com.limechain.trie.decoded.TrieVerifier; -import com.limechain.exception.trie.TrieDecoderException; import com.limechain.utils.LittleEndianUtils; import com.limechain.utils.RandomGenerationUtils; import com.limechain.utils.StringUtils;