Skip to content

Commit

Permalink
Merge pull request #2653 from rsksmart/feature/add_snap_syncing_in_cl…
Browse files Browse the repository at this point in the history
…i_args

Enable snap syncing with RSK cli args
  • Loading branch information
Vovchyk authored Aug 8, 2024
2 parents ecdb18b + 11e2b73 commit 2d59ae7
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 5 deletions.
15 changes: 15 additions & 0 deletions rskj-core/src/main/java/co/rsk/cli/RskCli.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@CommandLine.Command(name = "rskj", mixinStandardHelpOptions = true, versionProvider = VersionProviderUtil.class,
description = "RSKJ blockchain node implementation in Java")
public class RskCli implements Runnable {
Expand Down Expand Up @@ -76,6 +77,12 @@ static class NetworkFlags {
@CommandLine.Option(names = {"-X"}, description = "Read arguments in command line")
private List<String> xArguments;

@CommandLine.Option(names = {"--sync-mode"}, description = "Set Synchronization mode. Valid options are <full | snap>")
private String syncMode;

@CommandLine.Option(names = {"--snap-nodes"}, description = "Set snapboot nodes")
private List<String> snapBootNodes;

private boolean help;
private boolean version;

Expand Down Expand Up @@ -153,6 +160,14 @@ private void loadCliArgs() {
}
}

if (syncMode != null) {
activatedOptions.put(NodeCliOptions.SYNC_MODE, syncMode);
}

if (snapBootNodes != null) {
activatedOptions.put(NodeCliOptions.SNAP_NODES, String.join(",", snapBootNodes));
}

cliArgs = CliArgs.of(activatedOptions, activatedFlags, paramValueMap);
}

Expand Down
51 changes: 51 additions & 0 deletions rskj-core/src/main/java/co/rsk/config/NodeCliOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,16 @@

import co.rsk.cli.OptionalizableCliArg;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigObject;
import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueFactory;
import org.ethereum.config.SystemProperties;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
* Options that the node can receive via command line arguments.
* E.g. -datadir /path/to/datadir
Expand All @@ -41,6 +48,50 @@ public Config withConfig(Config config, String configValue) {
return config.withValue(SystemProperties.PROPERTY_BASE_PATH, ConfigValueFactory.fromAnyRef(configValue));
}
},
SYNC_MODE("sync-mode", true) {
@Override
public Config withConfig(Config config, String configValue) {
SyncMode mode;
try {
mode = SyncMode.valueOf(configValue.toUpperCase());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid sync mode: " + configValue + ". The valid options are <full> or <snap>.");
}

if (mode == SyncMode.SNAP) {
return config.withValue(RskSystemProperties.PROPERTY_SNAP_CLIENT_ENABLED, ConfigValueFactory.fromAnyRef(true));
}
return config;
}
},
SNAP_NODES("snap-nodes", true) {
@Override
public Config withConfig(Config config, String configValue) {
try {
List<ConfigObject> snapConfigObjects = Arrays.stream(configValue.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(this::createConfigObjectFromSnapNode)
.collect(Collectors.toList());

if(!snapConfigObjects.isEmpty()) {
ConfigValue snapConfigValue = ConfigValueFactory.fromIterable(snapConfigObjects);
return config.withValue(RskSystemProperties.PROPERTY_SNAP_NODES, snapConfigValue);
}
return config;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("expecting URL in the format enode://PUBKEY@HOST:PORT", e);
}
}
private ConfigObject createConfigObjectFromSnapNode(String snapNode) {
try {
return ConfigValueFactory.fromMap(Collections.singletonMap("url", ConfigValueFactory.fromAnyRef(snapNode)));
} catch (Exception e) {
throw new RuntimeException("Error processing SnapBoot Nodes configuration. Ensure the URL format is 'enode://PUBKEY@HOST:PORT'.");
}
}
}
;

private final String optionName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ public class RskSystemProperties extends SystemProperties {
public static final String PROPERTY_SYNC_TOP_BEST = "sync.topBest";
public static final String USE_PEERS_FROM_LAST_SESSION = "peer.discovery.usePeersFromLastSession";

public static final String PROPERTY_SNAP_CLIENT_ENABLED = "sync.snapshot.client.enabled";
public static final String PROPERTY_SNAP_NODES = "sync.snapshot.client.snapBootNodes";

//TODO: REMOVE THIS WHEN THE LocalBLockTests starts working with REMASC
private boolean remascEnabled = true;

Expand Down Expand Up @@ -408,7 +411,7 @@ public int getLongSyncLimit() {
}

public boolean isServerSnapshotSyncEnabled() { return configFromFiles.getBoolean("sync.snapshot.server.enabled");}
public boolean isClientSnapshotSyncEnabled() { return configFromFiles.getBoolean("sync.snapshot.client.enabled");}
public boolean isClientSnapshotSyncEnabled() { return configFromFiles.getBoolean(PROPERTY_SNAP_CLIENT_ENABLED);}

public int getSnapshotChunkTimeout() {
return configFromFiles.getInt("sync.snapshot.client.chunkRequestTimeout");
Expand Down
23 changes: 23 additions & 0 deletions rskj-core/src/main/java/co/rsk/config/SyncMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* This file is part of RskJ
* Copyright (C) 2018 RSK Labs Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package co.rsk.config;

public enum SyncMode {
FULL,
SNAP
}
79 changes: 75 additions & 4 deletions rskj-core/src/test/java/co/rsk/config/RskSystemPropertiesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@

package co.rsk.config;

import co.rsk.cli.CliArgs;
import co.rsk.cli.RskCli;
import co.rsk.rpc.ModuleDescription;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigFactory;
import org.ethereum.net.rlpx.Node;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

import java.util.List;
import java.util.Map;
Expand All @@ -45,8 +44,6 @@
class RskSystemPropertiesTest {

private final TestSystemProperties config = new TestSystemProperties();
@Mock
private CliArgs<NodeCliOptions, NodeCliFlags> cliArgs;

@Test
void defaultValues() {
Expand Down Expand Up @@ -135,6 +132,80 @@ void testRpcModules() {

assertTrue(enabledModuleNames.stream().allMatch(k -> moduleNameEnabledMap.get(k).get(0).isEnabled()));
}

@Test
void rskCliSnapNodes_ShouldSetSnapBootNodes() {
RskCli rskCli = new RskCli();
String[] snapNodesArgs = {
"--snap-nodes=enode://b2a304b30b3ff90aabcb5e37fa3cc70511c9f5bf457d6d8bfb6f0905baf6d714b66a73fede2ea0671b3a4d1af2aed3379d7eb9340d775ae27800e0757dc1e502@3.94.45.146:50501",
"--snap-nodes=enode://b2a304b30b3ff90bbbcb5e37fa3cc70511c9f5bf457d6d8bfb6f0905baf6d714b66a73fede2ea0671b3a4d1af2aed3379d7eb9340d775ae27800e0757dc10502@3.94.45.146:50501"
};
rskCli.load(snapNodesArgs);

RskSystemProperties rskSystemProperties = new RskSystemProperties(
new ConfigLoader(
rskCli.getCliArgs()
)
);

Node expectedFirstSnapNode = new Node("enode://b2a304b30b3ff90aabcb5e37fa3cc70511c9f5bf457d6d8bfb6f0905baf6d714b66a73fede2ea0671b3a4d1af2aed3379d7eb9340d775ae27800e0757dc1e502@3.94.45.146:50501");
Node expectedSecondSnapNode = new Node("enode://b2a304b30b3ff90bbbcb5e37fa3cc70511c9f5bf457d6d8bfb6f0905baf6d714b66a73fede2ea0671b3a4d1af2aed3379d7eb9340d775ae27800e0757dc10502@3.94.45.146:50501");

Assertions.assertEquals(2, rskSystemProperties.getSnapBootNodes().size());
Assertions.assertEquals(expectedFirstSnapNode.getHexId(), rskSystemProperties.getSnapBootNodes().get(0).getHexId());
Assertions.assertEquals(expectedSecondSnapNode.getHexId(), rskSystemProperties.getSnapBootNodes().get(1).getHexId());
Assertions.assertEquals(expectedFirstSnapNode.getId(), rskSystemProperties.getSnapBootNodes().get(0).getId());
Assertions.assertEquals(expectedSecondSnapNode.getId(), rskSystemProperties.getSnapBootNodes().get(1).getId());
}

@Test
void rskCliSnapNodes_ShouldReturnZeroSnapBootNodesForInvalidNodeFormat() {
RskCli rskCli = new RskCli();
String[] snapNodesArgs = {
"--snap-nodes=http://www.google.es",
};

rskCli.load(snapNodesArgs);

Assertions.assertThrows(RuntimeException.class, () -> {
RskSystemProperties rskSystemProperties = new RskSystemProperties(
new ConfigLoader(rskCli.getCliArgs())
);

Assertions.assertEquals(0, rskSystemProperties.getSnapBootNodes().size());
});
}

@Test
void rskCliSyncMode_ShouldSetSyncMode() {
RskCli rskCli = new RskCli();
String[] snapNodesArgs = {"--sync-mode=snap"};
rskCli.load(snapNodesArgs);

RskSystemProperties rskSystemProperties = new RskSystemProperties(
new ConfigLoader(
rskCli.getCliArgs()
)
);

Assertions.assertTrue(rskSystemProperties.isClientSnapshotSyncEnabled());
}

@Test
void rskCliSyncMode_ShouldSetDefaultSyncMode() {
RskCli rskCli = new RskCli();
String[] snapNodesArgs = {"--sync-mode=full"};
rskCli.load(snapNodesArgs);

RskSystemProperties rskSystemProperties = new RskSystemProperties(
new ConfigLoader(
rskCli.getCliArgs()
)
);

Assertions.assertFalse(rskSystemProperties.isClientSnapshotSyncEnabled());
}

@Test
void testGetRpcModulesWithList() {
TestSystemProperties testSystemProperties = new TestSystemProperties(rawConfig ->
Expand Down

0 comments on commit 2d59ae7

Please sign in to comment.