Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Add NodeService and ServiceState interfaces #688

Merged
merged 5 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/main/java/com/limechain/NodeService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.limechain;

public interface NodeService {

void start();

void stop();
}
10 changes: 10 additions & 0 deletions src/main/java/com/limechain/ServiceState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.limechain;

public interface ServiceState {

void initialize();

void initializeFromDatabase();

void persistState();
}
4 changes: 2 additions & 2 deletions src/main/java/com/limechain/babe/BabeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import com.limechain.runtime.Runtime;
import com.limechain.runtime.RuntimeBuilder;
import com.limechain.storage.block.BlockHandler;
import com.limechain.storage.block.BlockState;
import com.limechain.storage.block.state.BlockState;
import com.limechain.storage.crypto.KeyStore;
import com.limechain.storage.crypto.KeyType;
import com.limechain.transaction.TransactionState;
Expand Down Expand Up @@ -252,7 +252,7 @@ private BlockHeader getParentBlockHeader(BigInteger slotNum) {
throw new BlockStorageGenericException("Could not get best block header");
}

boolean parentIsGenesis = blockState.getGenesisHash().equals(parentHeader.getHash());
boolean parentIsGenesis = blockState.getGenesisBlockHeader().getHash().equals(parentHeader.getHash());
if (!parentIsGenesis) {
BigInteger bestBlockSlotNum = DigestHelper.getBabePreRuntimeDigest(parentHeader.getDigest())
.orElseThrow(() ->
Expand Down
28 changes: 24 additions & 4 deletions src/main/java/com/limechain/babe/state/EpochState.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import com.limechain.babe.api.BabeApiConfiguration;
import com.limechain.babe.consensus.BabeConsensusMessage;
import com.limechain.state.AbstractState;
import com.limechain.storage.KVRepository;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.math.BigInteger;
Expand All @@ -15,9 +18,10 @@
*/
@Getter
@Component
public class EpochState {
@RequiredArgsConstructor
public class EpochState extends AbstractState {

private boolean isInitialized = false;
private final KVRepository<String, Object> repository;

private long disabledAuthority;
private BigInteger slotDuration;
Expand All @@ -30,14 +34,30 @@ public class EpochState {
private EpochData nextEpochData;
private EpochDescriptor nextEpochDescriptor;

public void initialize(BabeApiConfiguration babeApiConfiguration) {
@Override
public void initialize() {
initialized = true;
//TODO: Find a way to initiate a runtime instance during node startup to populate from genesis.
//Epoch data gets populated via a runtime call at the end of the syncing process.
}

@Override
public void initializeFromDatabase() {
//TODO: Add methods to load epoch state data.
}

@Override
public void persistState() {
//TODO: Add methods to store epoch state data.
}

public void populateDataFromRuntime(BabeApiConfiguration babeApiConfiguration) {
this.slotDuration = babeApiConfiguration.getSlotDuration();
this.epochLength = babeApiConfiguration.getEpochLength();
this.currentEpochData = new EpochData(
babeApiConfiguration.getAuthorities(), babeApiConfiguration.getRandomness());
this.currentEpochDescriptor = new EpochDescriptor(
babeApiConfiguration.getConstant(), babeApiConfiguration.getAllowedSlots());
this.isInitialized = true;
}

public void updateNextEpochConfig(BabeConsensusMessage message) {
Expand Down
89 changes: 0 additions & 89 deletions src/main/java/com/limechain/client/AbstractNode.java

This file was deleted.

28 changes: 24 additions & 4 deletions src/main/java/com/limechain/client/AuthoringNode.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
package com.limechain.client;

public class AuthoringNode extends AbstractNode {
import com.limechain.babe.state.EpochState;
import com.limechain.grandpa.state.RoundState;
import com.limechain.network.NetworkService;
import com.limechain.rpc.server.AppBean;
import com.limechain.storage.block.state.BlockState;
import com.limechain.sync.SyncService;
import com.limechain.sync.state.SyncState;
import com.limechain.transaction.TransactionState;

@Override
public void start() {
super.start();
import java.util.List;
import java.util.Objects;

public class AuthoringNode extends HostNode {

public AuthoringNode() {
super(List.of(
//TODO Add babe and grandpa services.
Objects.requireNonNull(AppBean.getBean(NetworkService.class)),
Objects.requireNonNull(AppBean.getBean(SyncService.class))),
List.of(
Objects.requireNonNull(AppBean.getBean(BlockState.class)),
Objects.requireNonNull(AppBean.getBean(SyncState.class)),
Objects.requireNonNull(AppBean.getBean(EpochState.class)),
Objects.requireNonNull(AppBean.getBean(RoundState.class)),
Objects.requireNonNull(AppBean.getBean(TransactionState.class))));
}
}
26 changes: 20 additions & 6 deletions src/main/java/com/limechain/client/FullNode.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
package com.limechain.client;

import lombok.extern.java.Log;
import com.limechain.babe.state.EpochState;
import com.limechain.grandpa.state.RoundState;
import com.limechain.network.NetworkService;
import com.limechain.rpc.server.AppBean;
import com.limechain.storage.block.state.BlockState;
import com.limechain.sync.SyncService;
import com.limechain.sync.state.SyncState;

@Log
public class FullNode extends AbstractNode {
import java.util.List;
import java.util.Objects;

@Override
public void start() {
super.start();
public class FullNode extends HostNode {

public FullNode() {
super(List.of(
Objects.requireNonNull(AppBean.getBean(NetworkService.class)),
Objects.requireNonNull(AppBean.getBean(SyncService.class))),
List.of(
Objects.requireNonNull(AppBean.getBean(BlockState.class)),
Objects.requireNonNull(AppBean.getBean(SyncState.class)),
Objects.requireNonNull(AppBean.getBean(EpochState.class)),
Objects.requireNonNull(AppBean.getBean(RoundState.class))));
}
}
53 changes: 49 additions & 4 deletions src/main/java/com/limechain/client/HostNode.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
package com.limechain.client;

public interface HostNode {
import com.limechain.NodeService;
import com.limechain.ServiceState;
import com.limechain.constants.GenesisBlockHash;
import com.limechain.rpc.server.AppBean;
import com.limechain.storage.KVRepository;
import com.limechain.storage.block.state.BlockStateHelper;
import com.limechain.storage.trie.TrieStorage;
import com.limechain.trie.structure.TrieStructure;
import com.limechain.trie.structure.database.NodeData;

import java.math.BigInteger;
import java.util.List;

public abstract class HostNode {

protected final List<NodeService> services;
protected final List<ServiceState> states;

protected HostNode(List<NodeService> services, List<ServiceState> states) {
this.services = services;
this.states = states;
}

/**
* Starts the client by assigning all dependencies and services from the spring boot application's context
*
* @apiNote the RpcApp is assumed to have been started
* before constructing the clients in our current implementations,
* as starting the clients relies on the application context
* before constructing the clients in our current implementations,
* as starting the clients relies on the application context
*/
void start();
public void start() {
initializeStates();
services.forEach(NodeService::start);
}

protected void initializeStates() {
// TODO: Is there a better way to decide whether we've got any database written?
KVRepository<String, Object> db = AppBean.getBean(KVRepository.class); //presume this works

if (db == null) {
throw new IllegalStateException("Database is not initialized");
}
TrieStorage trieStorage = AppBean.getBean(TrieStorage.class);
// if: database has some persisted storage
if (db.find(BlockStateHelper.headerHashKey(BigInteger.ZERO)).isPresent()) {
states.forEach(ServiceState::initializeFromDatabase);
} else {
GenesisBlockHash genesisBlockHash = AppBean.getBean(GenesisBlockHash.class);
TrieStructure<NodeData> trie = genesisBlockHash.getGenesisTrie();
trieStorage.insertTrieStorage(trie);

states.forEach(ServiceState::initialize);
}
}
}
52 changes: 13 additions & 39 deletions src/main/java/com/limechain/client/LightClient.java
Original file line number Diff line number Diff line change
@@ -1,52 +1,26 @@
package com.limechain.client;

import com.limechain.network.Network;
import com.limechain.network.NetworkService;
import com.limechain.rpc.server.AppBean;
import com.limechain.sync.warpsync.WarpSyncMachine;
import lombok.SneakyThrows;
import lombok.extern.java.Log;
import com.limechain.storage.block.state.BlockState;
import com.limechain.sync.SyncService;
import com.limechain.sync.state.SyncState;

import java.util.logging.Level;
import java.util.List;
import java.util.Objects;

/**
* Main light client class that starts and stops execution of
* the client and hold references to dependencies
*/
@Log
public class LightClient implements HostNode {
// TODO: Add service dependencies i.e rpc, sync, network, etc.
// TODO: Do we need those as fields here...?
private final Network network;
private WarpSyncMachine warpSyncMachine;
public class LightClient extends HostNode {

/**
* @implNote the RpcApp is assumed to have been started before constructing the client,
* as it relies on the application context
*/
public LightClient() {
this.network = AppBean.getBean(Network.class);
}

/**
* Starts the light client by instantiating all dependencies and services
*/
@SneakyThrows
public void start() {
this.network.start();

while (true) {
if (network.getKademliaService().getBootNodePeerIds().size() > 0) {
if (this.network.getKademliaService().getSuccessfulBootNodes() > 0) {
log.log(Level.INFO, "Node successfully connected to a peer! Sync can start!");
this.warpSyncMachine = AppBean.getBean(WarpSyncMachine.class);
this.warpSyncMachine.start();
break;
} else {
this.network.updateCurrentSelectedPeer();
}
}
log.log(Level.INFO, "Waiting for peer connection...");
Thread.sleep(10000);
}
super(List.of(
Objects.requireNonNull(AppBean.getBean(NetworkService.class)),
Objects.requireNonNull(AppBean.getBean(SyncService.class))),
List.of(
Objects.requireNonNull(AppBean.getBean(BlockState.class)),
Objects.requireNonNull(AppBean.getBean(SyncState.class))));
}
}
6 changes: 3 additions & 3 deletions src/main/java/com/limechain/config/SystemInfo.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.limechain.config;

import com.limechain.chain.Chain;
import com.limechain.network.Network;
import com.limechain.storage.block.SyncState;
import com.limechain.network.NetworkService;
import com.limechain.sync.state.SyncState;
import lombok.Getter;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -27,7 +27,7 @@ public class SystemInfo {
private String hostVersion;
private final BigInteger highestBlock;

public SystemInfo(HostConfig hostConfig, Network network, SyncState syncState) {
public SystemInfo(HostConfig hostConfig, NetworkService network, SyncState syncState) {
georg-getz marked this conversation as resolved.
Show resolved Hide resolved
this.role = network.getNodeRole().name();
this.chain = hostConfig.getChain();
this.dbPath = hostConfig.getRocksDbPath();
Expand Down
Loading
Loading