diff --git a/convex-core/src/main/java/convex/core/cvm/ARecordGeneric.java b/convex-core/src/main/java/convex/core/cvm/ARecordGeneric.java index 0927377fb..8b928d8bf 100644 --- a/convex-core/src/main/java/convex/core/cvm/ARecordGeneric.java +++ b/convex-core/src/main/java/convex/core/cvm/ARecordGeneric.java @@ -120,8 +120,8 @@ public AVector values() { protected abstract ARecordGeneric withValues(AVector newValues); @Override - public void validateCell() throws InvalidDataException { - values.validateCell(); + protected void validateCell() throws InvalidDataException { + Cells.validateCell(values); } } diff --git a/convex-core/src/main/java/convex/core/cvm/Syntax.java b/convex-core/src/main/java/convex/core/cvm/Syntax.java index 3327d54e9..122e271c1 100644 --- a/convex-core/src/main/java/convex/core/cvm/Syntax.java +++ b/convex-core/src/main/java/convex/core/cvm/Syntax.java @@ -232,12 +232,12 @@ public boolean print(BlobBuilder bb, long limit) { public void validateCell() throws InvalidDataException { if (datumRef == null) throw new InvalidDataException("null datum ref", this); if (meta == null) throw new InvalidDataException("null metadata", this); - meta.validateCell(); + Cells.validateCell(meta);; } @Override - public void validate() throws InvalidDataException { - super.validate(); + public void validateStructure() throws InvalidDataException { + super.validateStructure(); ACell datum=datumRef.getValue(); if (datum!=null) { if (datum instanceof Syntax) { diff --git a/convex-core/src/main/java/convex/core/cvm/ops/AMultiOp.java b/convex-core/src/main/java/convex/core/cvm/ops/AMultiOp.java index 3de89a984..d5204124d 100644 --- a/convex-core/src/main/java/convex/core/cvm/ops/AMultiOp.java +++ b/convex-core/src/main/java/convex/core/cvm/ops/AMultiOp.java @@ -3,6 +3,7 @@ import convex.core.cvm.AOp; import convex.core.data.ACell; import convex.core.data.AVector; +import convex.core.data.Cells; import convex.core.data.Format; import convex.core.data.IRefFunction; import convex.core.data.Ref; @@ -62,6 +63,6 @@ public Ref getRef(int i) { @Override public void validateCell() throws InvalidDataException { - ops.validateCell(); + Cells.validateCell(ops); } } diff --git a/convex-core/src/main/java/convex/core/cvm/transactions/Call.java b/convex-core/src/main/java/convex/core/cvm/transactions/Call.java index e7705f587..db77d06a5 100644 --- a/convex-core/src/main/java/convex/core/cvm/transactions/Call.java +++ b/convex-core/src/main/java/convex/core/cvm/transactions/Call.java @@ -98,8 +98,8 @@ public Context apply(Context ctx) { @Override public void validateCell() throws InvalidDataException { + super.validateCell(); if (!Coin.isValidAmount(offer)) throw new InvalidDataException("Invalid offer",this); - target.validateCell(); } @Override diff --git a/convex-core/src/main/java/convex/core/cvm/transactions/Invoke.java b/convex-core/src/main/java/convex/core/cvm/transactions/Invoke.java index 6e9a43896..de3103dfc 100644 --- a/convex-core/src/main/java/convex/core/cvm/transactions/Invoke.java +++ b/convex-core/src/main/java/convex/core/cvm/transactions/Invoke.java @@ -10,13 +10,11 @@ import convex.core.data.ACell; import convex.core.data.AVector; import convex.core.data.Blob; -import convex.core.data.Cells; import convex.core.data.Format; import convex.core.data.Keyword; import convex.core.data.Vectors; import convex.core.data.prim.CVMLong; import convex.core.exceptions.BadFormatException; -import convex.core.exceptions.InvalidDataException; import convex.core.lang.Reader; import convex.core.util.ErrorMessages; @@ -112,16 +110,6 @@ public int estimatedEncodingSize() { return 1 + 12 + Format.MAX_EMBEDDED_LENGTH + Format.MAX_VLQ_LONG_LENGTH; } - @Override - public void validateCell() throws InvalidDataException { - if (command instanceof AOp) { - // OK? - ((AOp) command).validateCell(); - } else { - if (!Cells.isCanonical(command)) throw new InvalidDataException("Non-canonical object as command?", this); - } - } - @Override public Invoke withSequence(long newSequence) { if (newSequence==this.sequence) return this; diff --git a/convex-core/src/main/java/convex/core/data/AArrayBlob.java b/convex-core/src/main/java/convex/core/data/AArrayBlob.java index 8f1bb37b5..2ab25693e 100644 --- a/convex-core/src/main/java/convex/core/data/AArrayBlob.java +++ b/convex-core/src/main/java/convex/core/data/AArrayBlob.java @@ -368,6 +368,11 @@ public void validateCell() throws InvalidDataException { "End out of range: " + (offset + count) + " with array size=" + store.length, this); } } + + @Override + protected void validateStructure() { + // nothing to do by default + } @Override public long longValue() { diff --git a/convex-core/src/main/java/convex/core/data/ABlob.java b/convex-core/src/main/java/convex/core/data/ABlob.java index f60272a10..b39ca9358 100644 --- a/convex-core/src/main/java/convex/core/data/ABlob.java +++ b/convex-core/src/main/java/convex/core/data/ABlob.java @@ -272,7 +272,7 @@ public void validate() throws InvalidDataException { } @Override - public void validateCell() throws InvalidDataException { + protected void validateCell() throws InvalidDataException { if (count() < 0) throw new InvalidDataException("Negative blob length", this); } diff --git a/convex-core/src/main/java/convex/core/data/ACAD3Record.java b/convex-core/src/main/java/convex/core/data/ACAD3Record.java index 6c2892496..55d5a6fbc 100644 --- a/convex-core/src/main/java/convex/core/data/ACAD3Record.java +++ b/convex-core/src/main/java/convex/core/data/ACAD3Record.java @@ -29,7 +29,11 @@ public void validateCell() throws InvalidDataException { default: throw new InvalidDataException("Bad tag for CAD3 Record: 0x"+Utils.toHexString(tag),this); } } - + + @Override + protected void validateStructure() throws InvalidDataException { + // Nothing to do, any child refs are valid + } @Override public boolean equals(ACell a) { diff --git a/convex-core/src/main/java/convex/core/data/ACell.java b/convex-core/src/main/java/convex/core/data/ACell.java index 95c4961a0..1461acf69 100644 --- a/convex-core/src/main/java/convex/core/data/ACell.java +++ b/convex-core/src/main/java/convex/core/data/ACell.java @@ -35,7 +35,7 @@ public void validate() throws InvalidDataException { } /** - * Validates the local structure and invariants of this cell. Called by validate() super implementation. + * Validates the local structure and invariants of this cell. * * Should validate directly contained data, but should not validate all other structure of this cell. * @@ -43,7 +43,19 @@ public void validate() throws InvalidDataException { * * @throws InvalidDataException If the Cell is invalid */ - public abstract void validateCell() throws InvalidDataException; + protected abstract void validateCell() throws InvalidDataException; + + /** + * Validates the structure and invariants of this cell. + * + * May visit child refs. Should complete in O(1) time. + * + * @throws InvalidDataException If the Cell is invalid + */ + protected void validateStructure() throws InvalidDataException { + // nothing by default + } + /** * Hash of data Encoding of this cell, equivalent to the Value ID. Calling this method diff --git a/convex-core/src/main/java/convex/core/data/ASymbolic.java b/convex-core/src/main/java/convex/core/data/ASymbolic.java index 7d2cbe681..d219d1072 100644 --- a/convex-core/src/main/java/convex/core/data/ASymbolic.java +++ b/convex-core/src/main/java/convex/core/data/ASymbolic.java @@ -78,6 +78,12 @@ public final int hashCode() { @Override public abstract void validateCell() throws InvalidDataException; + @Override + public void validateStructure() throws InvalidDataException { + // nothing to do by default, covered by validateCell in general + } + + @Override public byte byteAt(long i) { // TODO Auto-generated method stub diff --git a/convex-core/src/main/java/convex/core/data/BlobTree.java b/convex-core/src/main/java/convex/core/data/BlobTree.java index 6fe59f761..db563cbed 100644 --- a/convex-core/src/main/java/convex/core/data/BlobTree.java +++ b/convex-core/src/main/java/convex/core/data/BlobTree.java @@ -432,21 +432,24 @@ public Blob getChunk(long chunkIndex) { int child = Utils.checkedInt(chunkIndex >> shift); return getChild(child).getChunk(chunkIndex - child * childSize); } - + @Override - public void validate() throws InvalidDataException { - super.validate(); + public void validateCell() throws InvalidDataException { int n = children.length; if ((n < 2) | (n > FANOUT)) throw new InvalidDataException("Illegal number of BlobTree children: " + n, this); + } + + @Override + public void validateStructure() throws InvalidDataException { long clen = childLength(); long total = 0; + int n = children.length; // We need to validate and check the lengths of all child notes. Note that only the last child can // be shorted than the defined childLength() for this shift level. for (int i = 0; i < n; i++) { ABlob child; child = getChild(i); - child.validate(); long cl = child.count(); total += cl; @@ -477,11 +480,6 @@ public boolean appendHex(BlobBuilder bb, long length) { return true; } - @Override - public void validateCell() throws InvalidDataException { - int n = children.length; - if ((n < 2) | (n > FANOUT)) throw new InvalidDataException("Illegal number of BlobTree children: " + n, this); - } @Override public long hexMatch(ABlobLike b) { diff --git a/convex-core/src/main/java/convex/core/data/Cells.java b/convex-core/src/main/java/convex/core/data/Cells.java index d3e38cdb6..da87aa9b2 100644 --- a/convex-core/src/main/java/convex/core/data/Cells.java +++ b/convex-core/src/main/java/convex/core/data/Cells.java @@ -332,6 +332,7 @@ public static void validate(ACell cell) throws InvalidDataException { Ref ref=cell.getRef(); if (ref.isValidated()) return; cell.validateCell(); + cell.validateStructure(); } /** @@ -384,6 +385,11 @@ public static int getEncodingLength(ACell value) { return value.getEncodingLength(); } + public static void validateCell(ACell a) throws InvalidDataException { + if (a==null) return; + a.validateCell(); + } + } diff --git a/convex-core/src/main/java/convex/core/data/CodedValue.java b/convex-core/src/main/java/convex/core/data/CodedValue.java index 0d1efeaff..e6ac8842d 100644 --- a/convex-core/src/main/java/convex/core/data/CodedValue.java +++ b/convex-core/src/main/java/convex/core/data/CodedValue.java @@ -30,6 +30,11 @@ public int estimatedEncodingSize() { public void validateCell() throws InvalidDataException { // Nothing to do } + + @Override + protected void validateStructure() throws InvalidDataException { + // Nothing to do, any child refs are valid + } @Override public byte getTag() { @@ -116,4 +121,6 @@ public static CodedValue read(byte tag, Blob b, int pos) throws BadFormatExcepti } return result; } + + } diff --git a/convex-core/src/main/java/convex/core/data/Format.java b/convex-core/src/main/java/convex/core/data/Format.java index 0af857c79..4433167d0 100644 --- a/convex-core/src/main/java/convex/core/data/Format.java +++ b/convex-core/src/main/java/convex/core/data/Format.java @@ -951,6 +951,8 @@ public static void decodeCells(HashMap acc, Blob data) throws BadFor * @return Blob encoding */ public static Blob encodeMultiCell(ACell a, boolean everything) { + if (a==null) return Blob.NULL_ENCODING; + Blob topCellEncoding=Cells.encode(a); if (a.getRefCount()==0) return topCellEncoding; @@ -974,7 +976,10 @@ public static Blob encodeMultiCell(ACell a, boolean everything) { int cellLength=lengthFieldSize+encLength; int newLength=ml[0]+cellLength; - if (newLength>CPoSConstants.MAX_MESSAGE_LENGTH) return; + if (newLength>CPoSConstants.MAX_MESSAGE_LENGTH) { + System.err.println("Exceeded max message length when encoding"); + return; + } ml[0]=newLength; refs.add(cr); if (everything) Cells.visitBranchRefs(c, addToStackFunc); diff --git a/convex-core/src/main/java/convex/core/data/Index.java b/convex-core/src/main/java/convex/core/data/Index.java index d0716d8c2..92d366a00 100644 --- a/convex-core/src/main/java/convex/core/data/Index.java +++ b/convex-core/src/main/java/convex/core/data/Index.java @@ -630,54 +630,6 @@ protected MapEntry getEntryByHash(Hash hash) { throw new UnsupportedOperationException(); } - @SuppressWarnings("unchecked") - @Override - public void validate() throws InvalidDataException { - super.validate(); - - if ((depth<0)||(depth>MAX_DEPTH)) throw new InvalidDataException("Invalid index depth",this); - - if (entry!=null) { - ABlobLike k=RT.ensureBlobLike(entry.getKey()); - if (k==null) throw new InvalidDataException("Invalid entry key type: "+Utils.getClassName(entry.getKey()),this); - if (depth!=effectiveLength(k)) throw new InvalidDataException("Entry at inconsistent depth",this); - } - - ABlobLike prefix=getPrefix(); - if (depth>effectiveLength(prefix)) throw new InvalidDataException("depth longer than common prefix",this); - - long ecount = (entry == null) ? 0 : 1; - int n = children.length; - for (int i = 0; i < n; i++) { - ACell o = children[i].getValue(); - if (!(o instanceof Index)) - throw new InvalidDataException("Illegal Index child type: " + Utils.getClass(o), this); - Index c = (Index) o; - - long ccount=c.count(); - if (ccount==0) { - throw new InvalidDataException("Child "+i+" should not be empty! At depth "+depth,this); - } - - if (c.getDepth() <= getDepth()) { - throw new InvalidDataException("Child must have greater depth than parent", this); - } - - ABlobLike childPrefix=c.getPrefix(); - long ml=prefix.hexMatch(childPrefix, 0, depth); - if (ml prefix) { return Math.min(MAX_DEPTH, prefix.hexLength()); @@ -728,6 +680,54 @@ public void validateCell() throws InvalidDataException { "Index with no entry and count=" + count + " must have two or more children", this); } } + + @SuppressWarnings("unchecked") + @Override + public void validate() throws InvalidDataException { + super.validate(); + + if ((depth<0)||(depth>MAX_DEPTH)) throw new InvalidDataException("Invalid index depth",this); + + if (entry!=null) { + ABlobLike k=RT.ensureBlobLike(entry.getKey()); + if (k==null) throw new InvalidDataException("Invalid entry key type: "+Utils.getClassName(entry.getKey()),this); + if (depth!=effectiveLength(k)) throw new InvalidDataException("Entry at inconsistent depth",this); + } + + ABlobLike prefix=getPrefix(); + if (depth>effectiveLength(prefix)) throw new InvalidDataException("depth longer than common prefix",this); + + long ecount = (entry == null) ? 0 : 1; + int n = children.length; + for (int i = 0; i < n; i++) { + ACell o = children[i].getValue(); + if (!(o instanceof Index)) + throw new InvalidDataException("Illegal Index child type: " + Utils.getClass(o), this); + Index c = (Index) o; + + long ccount=c.count(); + if (ccount==0) { + throw new InvalidDataException("Child "+i+" should not be empty! At depth "+depth,this); + } + + if (c.getDepth() <= getDepth()) { + throw new InvalidDataException("Child must have greater depth than parent", this); + } + + ABlobLike childPrefix=c.getPrefix(); + long ml=prefix.hexMatch(childPrefix, 0, depth); + if (ml> cref=children[i]; + if (cref == null) return false; } return true; } @Override public void validateCell() throws InvalidDataException { - if (shift<0) throw new InvalidDataException("Negaitive shift!", this); if (!isValidStructure()) throw new InvalidDataException("Bad structure", this); } diff --git a/convex-core/src/main/java/convex/core/data/VectorLeaf.java b/convex-core/src/main/java/convex/core/data/VectorLeaf.java index a0f85e3a1..1ca3c3d6b 100644 --- a/convex-core/src/main/java/convex/core/data/VectorLeaf.java +++ b/convex-core/src/main/java/convex/core/data/VectorLeaf.java @@ -716,7 +716,6 @@ public void validate() throws InvalidDataException { @Override public void validateCell() throws InvalidDataException { if ((count > 0) && (items.length == 0)) throw new InvalidDataException("Should be items present!", this); - if (!isCanonical()) throw new InvalidDataException("Not a canonical VectorLeaf!", this); } diff --git a/convex-core/src/main/java/convex/core/data/VectorTree.java b/convex-core/src/main/java/convex/core/data/VectorTree.java index 1a4d2e62d..ffe9cc88f 100644 --- a/convex-core/src/main/java/convex/core/data/VectorTree.java +++ b/convex-core/src/main/java/convex/core/data/VectorTree.java @@ -671,13 +671,20 @@ public AVector slice(long start, long end) { public AVector next() { return slice(1L, count); } + + @Override + protected void validateCell() throws InvalidDataException { + if (!isPacked()) throw new InvalidDataException("Non packed VectorTree size", this); + int blen = children.length; + if (blen < 2) throw new InvalidDataException("Insufficient children", this); + if (count <= childSize()*(blen-1)) throw new InvalidDataException("Impossible low count", this); + } @Override - public void validate() throws InvalidDataException { - super.validate(); + protected void validateStructure() throws InvalidDataException { + super.validateStructure(); long c = 0; int blen = children.length; - if (blen < 2) throw new InvalidDataException("Insufficient children: " + blen, this); if (count < MINIMUM_SIZE) throw new InvalidDataException("Insufficient elements: " + blen, this); long bsize = childSize(); for (int i = 0; i < blen; i++) { @@ -686,7 +693,6 @@ public void validate() throws InvalidDataException { @SuppressWarnings("unchecked") AVector b=(AVector)ch; - b.validate(); long expectedChildSize=childSize(count,i); if (expectedChildSize != b.count()) { throw new InvalidDataException("Expected block size: " + bsize + " for blocks[" + i + "] but was: " @@ -700,14 +706,6 @@ public void validate() throws InvalidDataException { } } - @Override - public void validateCell() throws InvalidDataException { - if (!isPacked()) throw new InvalidDataException("Non packed VectorTree size", this); - int blen = children.length; - if (blen < 2) throw new InvalidDataException("Insufficient children", this); - if (count <= childSize()*(blen-1)) throw new InvalidDataException("Impossible low count", this); - } - @Override public boolean equals(AVector o) { if (this==o) return true; diff --git a/convex-core/src/main/java/convex/core/lang/RT.java b/convex-core/src/main/java/convex/core/lang/RT.java index cad593456..69a51db58 100644 --- a/convex-core/src/main/java/convex/core/lang/RT.java +++ b/convex-core/src/main/java/convex/core/lang/RT.java @@ -1506,20 +1506,6 @@ public static void validate(Object o) throws InvalidDataException { } - /** - * Validate a Cell. - * - * @param o Object to validate - * @throws InvalidDataException For any validation failure - */ - public static void validateCell(ACell o) throws InvalidDataException { - if (o == null) - return; - if (o instanceof ACell) { - ((ACell) o).validateCell(); - } - } - /** * Associates a key position with a given value in an associative data structure * diff --git a/convex-core/src/main/java/convex/core/lang/impl/ADataFn.java b/convex-core/src/main/java/convex/core/lang/impl/ADataFn.java index 1f7a872b4..7ba02dbd2 100644 --- a/convex-core/src/main/java/convex/core/lang/impl/ADataFn.java +++ b/convex-core/src/main/java/convex/core/lang/impl/ADataFn.java @@ -32,7 +32,7 @@ public boolean hasArity(int n) { @Override public void validateCell() throws InvalidDataException { - getCanonical().validateCell();; + // nothing to do? } @Override diff --git a/convex-core/src/test/java/convex/core/data/AdversarialDataTest.java b/convex-core/src/test/java/convex/core/data/AdversarialDataTest.java index 7c99d3485..bf23499e6 100644 --- a/convex-core/src/test/java/convex/core/data/AdversarialDataTest.java +++ b/convex-core/src/test/java/convex/core/data/AdversarialDataTest.java @@ -273,6 +273,11 @@ public void testBadBlock() { } + @Test + public void testBadSet() { + invalidEncoding("83851d3ff0000000000000"); + } + @Test public void testBadAccountStatus() { // TODO: what should happen here? @@ -296,6 +301,7 @@ public void testBadCharacter() { invalidEncoding("3d110000"); // just beyond maximum code point invalidEncoding("3f0fffffff"); // way beyond max code point invalidEncoding("3fffffffff"); // way beyond max code point, also negative int + } protected void invalidEncoding(int tag, String more) { diff --git a/convex-peer/src/main/java/convex/net/Message.java b/convex-peer/src/main/java/convex/net/Message.java index 7ec300dd9..5f9ddde6e 100644 --- a/convex-peer/src/main/java/convex/net/Message.java +++ b/convex-peer/src/main/java/convex/net/Message.java @@ -169,7 +169,7 @@ public Blob getMessageData() { break; default: - messageData=Cells.encode(payload); + messageData=Format.encodeMultiCell(payload,true); } return messageData; diff --git a/convex-peer/src/main/java/convex/peer/Config.java b/convex-peer/src/main/java/convex/peer/Config.java index a7df37693..5e603bebb 100644 --- a/convex-peer/src/main/java/convex/peer/Config.java +++ b/convex-peer/src/main/java/convex/peer/Config.java @@ -88,7 +88,7 @@ public class Config { /** * Size of incoming Belief queue */ - public static final int BELIEF_QUEUE_SIZE = 200; + public static final int BELIEF_QUEUE_SIZE = 500; /** * Checks if the config specifies a valid store diff --git a/convex-peer/src/main/java/convex/peer/Server.java b/convex-peer/src/main/java/convex/peer/Server.java index 8da4355d2..c6aa5d9ed 100644 --- a/convex-peer/src/main/java/convex/peer/Server.java +++ b/convex-peer/src/main/java/convex/peer/Server.java @@ -125,7 +125,6 @@ public class Server implements Closeable { /** * Configuration */ - private final HashMap config; /** @@ -496,7 +495,7 @@ public Address getPeerController() { } /** - * Adds an event to the inbound server event queue. May block. + * Adds an event to the inbound server event queue. * @param event Signed event to add to inbound event queue * @return True if Belief was successfullly queued, false otherwise */