From b4903fadf410d10eaf3ec6812a1a5a5d8c799337 Mon Sep 17 00:00:00 2001 From: mikera Date: Tue, 8 Oct 2024 23:53:35 +0100 Subject: [PATCH] Edits to support --genesis option on peer start --- Dockerfile | 2 +- .../main/java/convex/cli/peer/PeerStart.java | 43 ++++++++++++---- .../main/java/convex/core/data/MapTree.java | 7 ++- .../test/java/convex/core/data/SetsTest.java | 51 ++++++++++++++++++- .../test/java/convex/core/lang/CoreTest.java | 1 + 5 files changed, 90 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index cb62add10..4c7c58aca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,5 +27,5 @@ EXPOSE 443 VOLUME ["/etc/ssl/certs"] VOLUME ["/etc/convex/keystore"] -ENTRYPOINT ["java", "-jar", "convex.jar", "local", "start"] +ENTRYPOINT ["java", "-jar", "convex.jar", "peer", "start"] diff --git a/convex-cli/src/main/java/convex/cli/peer/PeerStart.java b/convex-cli/src/main/java/convex/cli/peer/PeerStart.java index ad95e5473..0def650f1 100644 --- a/convex-cli/src/main/java/convex/cli/peer/PeerStart.java +++ b/convex-cli/src/main/java/convex/cli/peer/PeerStart.java @@ -11,10 +11,13 @@ import convex.cli.ExitCodes; import convex.cli.mixins.RemotePeerMixin; import convex.core.crypto.AKeyPair; +import convex.core.cvm.State; import convex.core.data.AccountKey; import convex.core.data.Address; +import convex.core.data.Blob; import convex.core.data.Keyword; import convex.core.data.Keywords; +import convex.core.init.Init; import convex.etch.EtchStore; import convex.peer.API; import convex.peer.ConfigException; @@ -56,12 +59,18 @@ public class PeerStart extends APeerCommand { description = "Port number for the peer. Default is ${DEFAULT-VALUE}. If set to 0, will choose a random port.") private int port = 0; - @Option(names = { "--url" }, description = "URL for the peer to publish. If not provided, the peer will have no public URL.") + @Option(names = { "--url" }, + description = "URL for the peer to publish. If not provided, the peer will have no public URL.") private String url; @Option(names = { "--norest" }, description = "Disable REST srever.") private boolean norest; + @Option(names = { "--genesis" }, + defaultValue = "${env:CONVEX_GENESIS_SEED}", + description = "Governance seed for network genesis. For testing use only.") + private String genesis; + @Option(names = { "--api-port" }, defaultValue = "8080", description = "Port for REST API.") @@ -115,15 +124,25 @@ public void execute() throws InterruptedException { storeMixin.ensureKeyStore(); try (EtchStore store = etchMixin.getEtchStore()) { - - AKeyPair peerKey=findPeerKey(store); - if (peerKey==null) { - informWarning("No --peer-key specified or inferred from Etch Store "+store); - showUsage(); - return; + AKeyPair peerKey; + AKeyPair genesisKey=null; + if (genesis!=null&&(!genesis.isEmpty())) { + paranoia("Should't use Genesis Seed in strict security mode! Consider key compromised!"); + Blob seed=Blob.parse(genesis); + if (seed.count()!=32) { + throw new CLIError("Genesis seed must be 32 byte hex blob"); + } + peerKey = AKeyPair.create(seed); + genesisKey=peerKey; + informWarning("Using test genesis seed: "+seed); + } else { + peerKey=findPeerKey(store); + if (peerKey==null) { + informWarning("No --peer-key specified or inferred from Etch Store "+store); + showUsage(); + return; + } } - - inform("Preparing to start peer: "+peerKey.getAccountKey()); Address controller=Address.parse(controllerAddress); if (controller==null) { @@ -136,6 +155,12 @@ public void execute() throws InterruptedException { HashMap config=new HashMap<>(); config.put(Keywords.KEYPAIR, peerKey); config.put(Keywords.STORE, store); + if (genesisKey!=null) { + AccountKey gpk=genesisKey.getAccountKey(); + State state=Init.createState(gpk,gpk,List.of(gpk)); + informWarning("Greated genesis State: "+state.getHash()); + config.put(Keywords.STATE, state); + } Server server=API.launchPeer(config); if (!norest) { diff --git a/convex-core/src/main/java/convex/core/data/MapTree.java b/convex-core/src/main/java/convex/core/data/MapTree.java index e31a963d2..5fd7d9ece 100644 --- a/convex-core/src/main/java/convex/core/data/MapTree.java +++ b/convex-core/src/main/java/convex/core/data/MapTree.java @@ -13,6 +13,7 @@ import convex.core.exceptions.BadFormatException; import convex.core.exceptions.InvalidDataException; import convex.core.exceptions.TODOException; +import convex.core.lang.RT; import convex.core.exceptions.Panic; import convex.core.util.Bits; import convex.core.util.MergeFunction; @@ -859,8 +860,10 @@ protected void validateWithPrefix(Hash prefix, int shift) throws InvalidDataExce throw new InvalidDataException( "Expected AHashMap child at " + prefix + Utils.toHexChar(digitForIndex(i, mask)), this); } - @SuppressWarnings("unchecked") - AHashMap child = (AHashMap) o; + AHashMap child = RT.ensureHashMap(o); + if (child==null) { + throw new InvalidDataException("Non-hashmap child at position "+i,this); + } if (child.isEmpty()) throw new InvalidDataException("Empty child at " + prefix + Utils.toHexChar(digitForIndex(i, mask)), this); diff --git a/convex-core/src/test/java/convex/core/data/SetsTest.java b/convex-core/src/test/java/convex/core/data/SetsTest.java index f4e9072e2..3582222bf 100644 --- a/convex-core/src/test/java/convex/core/data/SetsTest.java +++ b/convex-core/src/test/java/convex/core/data/SetsTest.java @@ -16,6 +16,9 @@ import convex.core.lang.RT; import convex.test.Samples; +/** + * Tests for general set behaviour and logic + */ public class SetsTest { @Test @@ -23,6 +26,8 @@ public void testEmptySet() { ASet e = Sets.empty(); assertEquals(0, e.size()); assertFalse(e.contains(null)); + assertSame(e,Sets.create(Vectors.empty())); + assertSame(e,Sets.of(1).exclude(CVMLong.ONE)); } @Test @@ -35,11 +40,15 @@ public void testIncludeExclude() { assertEquals("#{1}", s.toString()); s = s.include(RT.cvm(2L)); assertEquals("#{2,1}", s.toString()); + assertSame(s,s.exclude(null)); + s = s.exclude(RT.cvm(1L)); assertEquals("#{2}", s.toString()); s = s.exclude(RT.cvm(2L)); - assertTrue(s.isEmpty()); - assertSame(s, Sets.empty()); + assertSame(Sets.empty(),s); + + s = s.exclude(RT.cvm(2L)); + assertSame(Sets.empty(),s); } @Test @@ -47,6 +56,7 @@ public void testSetEncoding() { // Set should be encoded as a map with different tag and extra value Ref(s) ASet s=Sets.of(123); AMap m=Maps.of(123,null); + // compare encodings ignoring tag assertEquals(m.getEncoding().slice(1),s.getEncoding().append(Blob.SINGLE_ZERO).slice(1)); } @@ -139,6 +149,14 @@ public void testMergingIdentity() { assertSame(a, a.includeAll(Sets.of(1L, 3L))); } + @Test + public void testNilMembership() { + ASet a = Sets.of(1, 2, 3, null); + assertTrue(a.containsKey(null)); + a=a.exclude(null); + assertEquals(3,a.size()); + } + @Test public void testIntersection() { ASet a = Sets.of(1, 2, 3); @@ -184,10 +202,16 @@ public void testBigSlice() { ObjectsTest.doEqualityTests(s,s1.includeAll(s2).includeAll(s3)); } + @SuppressWarnings("unchecked") @Test public void testBigMerging() { ASet s = Sets.create(Samples.INT_VECTOR_300); + assertEquals(0,((SetTree)s).shift); SetsTest.doSetTests(s); + + SetTree child=(SetTree)(s.getRef(1).getValue()); + assertEquals(1,child.shift); + SetsTest.doSetTests(child); ASet s2 = s.includeAll(Sets.of(1, 2, 3, 100)); assertEquals(s, s2); @@ -231,6 +255,29 @@ public void testIncrementalBuilding() { } doSetTests(set); + + // now build the same set in hash order + ASet set2=Sets.empty(); + for (int i=0; i<320; i++) { + assertEquals(i,set2.size()); + + // extend set with one new element + CVMLong v=set.get(i); + set2=set2.conj(v); + } + assertEquals(set2,set); + doSetTests(set); // check nothing is odd + + // now deconstruct the set in hash order + ASet set3=set2; + for (int i=0; i<320; i++) { + assertEquals(320-i,set3.size()); + + // extend set with one new element + CVMLong v=set.get(i); + set3=set3.exclude(v); + } + assertSame(Sets.EMPTY,set3); } /** diff --git a/convex-core/src/test/java/convex/core/lang/CoreTest.java b/convex-core/src/test/java/convex/core/lang/CoreTest.java index 52d4da454..bd4083a85 100644 --- a/convex-core/src/test/java/convex/core/lang/CoreTest.java +++ b/convex-core/src/test/java/convex/core/lang/CoreTest.java @@ -1935,6 +1935,7 @@ public void testInto() { assertEquals(Lists.of(2L, 1L, 3L, 4L), eval("(into '(3 4) '(1 2))")); assertEquals(Sets.of(1L, 2L, 3L), eval("(into #{} [1 2 1 2 3])")); + assertEquals(Sets.of(1L, 2L, 3L), eval("(into #{} #{1 2 3})")); // map as data structure assertEquals(Maps.empty(), eval("(into {} [])"));