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;