Code Monkey home page Code Monkey logo

convex's Introduction

Convex

Maven Central

Convex is a decentralised network and execution engine for the Internet of Value. It can be seen as an implementation of a "Stateful Internet" where the network itself securely hosts and executes code and data.

It is designed as a full stack solution for decentralised applications and programmable economic systems that manage digital assets, where asset ownership is cryptographically secured and can be managed (optionally) with Smart Contracts.

Convex is based on Lattice Technology, exploiting the mathematical properties of lattices to achieve efficient consensus and verifiability. Lattice technology can be used to solve problems in a similar manner to blockchains, but offers some significant advantages:

  • Global State model with immutable data structures and atomic transactions
  • Lambda Calculus based VM supporting Turing complete Smart Contracts
  • High transaction throughput (tens of thousands of write transactions per second, potentially scaling to millions in the future)
  • Simple networking protocol based on random gossip
  • Low latency for transaction confirmation (milliseconds for global consensus, depending on network speed)
  • 100% Green - energy efficiency using the Convergent Proof of Stake consensus algorithm
  • Integrated on-chain compiler (Convex Lisp)

About this repository

This repository contains the core Convex distribution including:

  • The Convex Virtual Machine (CVM) including data structures and execution environment
  • The standard Convex Peer server implementation (NIO based) implementing Convergent Proof of Stake (CPoS) for consensus
  • CLI Tools for operating Peers, scripting transactions and more
  • The Etch database for persistent data storage
  • A Swing GUI for managing local peers / exploring the network
  • A simple REST API server
  • JMH Benchmarking suite
  • Java Client API

The repository also contains core "on-chain" libraries providing key full-stack functionality and tools for decentralised applications, including:

  • convex.fungible - Fungible Tokens
  • asset.nft.simple - Basic lightweight Non-fungible tokens
  • convex.asset - library for managing arbitrary digital assets using a common abstraction
  • convex.trust - library for access control and trusted operations
  • torus.exchange - decentralised exchange for trading fungible tokens and currencies
  • Example code and templates for various forms of smart contracts

Modules

Name Description Maven Javadoc
convex-core CVM, data structures and consensus Maven Central javadoc
convex-peer Peer implementation and networking Maven Central javadoc
convex-cli Command Line Tools Maven Central javadoc
convex-gui Convex Desktop GUI Interface Maven Central javadoc

For making use of Convex data structures, CVM execution etc. locally you probably just need convex-core. If you want to run a Peer or talk to a Peer over the network, then you will need convex-peer as a dependency. The other modules are mainly intended to run as standalone applications.

Key features

  • Convex Virtual Machine (CVM) - The CVM provides a secure execution environment based on the Lambda Calculus and capable of acting as the execution layer for smart contracts and autonomous agents.
  • Decentralised Consensus - Similar to Blockchain technology, Convex incorporates a consensus mechanism that ensures all nodes ultimately agree on true values in the system without the control of any single entity. This property means that it is inherently tamper-proof and censorship-resistant.
  • Performance and Scalability - Convex is capable of executing large volumes of transactions (tens of thousands of transactions per second) with low latency (sub-second global consensus)
  • 100% Green - No wasteful consumption of energy or computing resources

Running Convex

Building locally

To get a local development build of Convex you need git and Apache Maven. You will also need a recent version of Java (JDK 21+ recommended, though anything from 17 onwards should be supported)

  1. Clone this repository using git - you probably want the develop branch (the default)
  2. Build using mvn install in the root directory

This should download all necessary dependencies and perform a standard build.

Convex Desktop

Convex Desktop is a GUI application for power users and developers providing full access to the capabilities of Convex. To run, you will need a modern version of Java installed (21+) and the convex-desktop.jar executable file (which can be found in the outputs of the Maven build above, or downloaded from trusted sources).

java -jar convex-desktop.jar

Command Line Interface (CLI)

If you have an already built version of the Convex CLI convex-cli.jar file and installed a recent version of Java you can run it as follows:

java -jar convex-cli.jar <optional args>

For convenience, there are shell scripts to automate this for common platforms in the root directory of this repo, e.g.

./convex --help

Using the CLI, you can start the Convex Desktop GUI for a local peer test network by using the local gui command:

./convex local gui

Contributing

Open Source contributions are welcome under the terms of the Convex Public License. Contributors retain copyright to their work, but must accept the terms of the license.

We have instituted a Contributors Agreement for all contributions to the core Convex repository.

The Convex Foundation may, at its sole discretion, award contributors with Convex Coins as recognition of value contributed to the Convex ecosystem. Convex coins are the native coin of the Convex network, and function as a utility token that provides the right to make use of the services of the network. Convex coins may be exchangeable for other digital assets and currencies.

Community

We use Discord as for discussing Convex - you can join the public server at https://discord.gg/5j2mPsk

Alternatively, email: info(at)convex.world

Copyright

Copyright 2017-2024 The Convex Foundation and Contributors

Unless otherwise specified, source code is available under the terms of the Convex Public License

convex's People

Contributors

anonymousaccount4se avatar billbsing avatar darkneew avatar deepheap avatar dependabot[bot] avatar eltociear avatar engelberg avatar hboutemy avatar helins avatar jcoultas avatar jeroenvandijk avatar kopcho avatar kroezone avatar linneman avatar miguel-depaz avatar mikera avatar oakes avatar omahs avatar pbaille avatar rosejn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

convex's Issues

EDN: Blob output is ill-suited

PROBLEM: When writing EDN, Blob outputs its content as a number in hexadecimal notation, meaning that the EDN reader interprets it as a long or a bigint (eg. Clojure's BigInt). While it somewhat works, it is highly uncomfortable. For instance, Clojure's BigInt do not support bitwise operations and any meaningful work becomes tedious.

FIX:

a) Output an actual hexstring, a proper string. Currently prevented by #53. Not perfect but arguably more amenable than a large number.

b) Output a vector of individual bytes. Technically accurate but can be slow for bigger data (especially in Clojure). On the other hand, data stored on chain should not be huge.

Missing `filter` in core

That was surprising but yes, filter is indeed missing in Core. For a language relying so much on functional programming, it should be added.

Edit: And similarly, filterv if a difference is ultimately implemented between map and mapv.

CVM String handling

The CVM will require special handling for non-embedded Strings that exceed a certain length (similar to Blob / BlobTree).

Need to implement:

  • Cut-off size beyond which Strings cease to be embedded
  • Cell-based wrapper for long strings
  • Update runtime functions to understand both String types (can probably both implement CharSequence for covenience)

Stringifying `MultiFn` returns invalid code

Either from the sandbox or directly on the CVM:

(fn ([]) ([a]))

;; => (fn (fn [] nil) (fn [a] nil))

Result is an invalid form, evaluating it produces:

Compile: fn instance requires a vector of parameters but got form: (fn [] nil)

Scrypt - let expressions

Scrypt should probably have a statement equivalent to the usual (let [...] ....) form in Lisp

Examples:

let (x=1) x+2;
let (a=1, b=a+1) {a * b;};
(1 + let (b=10) b*b)

Might need to think a bit about whether semicolons are mandatory. Probably not? We should perhaps think of this as a let expression rather than a statement?

NaN violates iEEE754

Namely:

(= NaN NaN)

;; True

The standard defines that this must be always false.

Scrypt - Syntax

@kroezone what do you have in mind for the syntax? Here's a Python-ish syntax:

Convex Lisp Convex Scrypt Python
(def x 1) def x: 1 x = 1
(defn inc [x] (+ x 1)) defn inc(x): x + 1 def inc(x): x + 1
(let [x 1 y 2] (+ x y)) let x = 1 y = 2 in: x + y -
(inc 1) inc(1) inc(1)
(do (println "Foo") 1) do: println("Foo") 1 -

Literal notation of blobs misbehave with odd-length hexstring

The length of a input hexstring for a Blob should be of even length. However, it seems the Reader is buggy and can't handle odd length at all:

0xfff
ERROR (UNDECLARED)
'xfff' is undeclared.

This is certainly confusing for the user.

On a similar note, fix to #54 works but the cast error remains cryptic to the user. Maybe hinting that a hexstring must be of even length? Otherwise it gives the impression that strings in general cannot be cast to blobs.

(blob "f")
ERROR (CAST)
Cast error: Can't convert f of class convex.core.data.StringShort to class class convex.core.data.ABlob.

Ensure fixed size Account records

There is a potential exploit with Memory Accounting if the Account records are not fixed size:

  1. Execute some setup code such that:
  2. Memory accounting causes at least one Account size to increase
  3. Execute some more code to make the Account size decrease (e.g. a transfer)
  4. Enjoy a memory refund
  5. Sell the memory for a profit
  6. Repeat

Might not be practical (the transaction of triggering the refund of 1-2 bytes may not be economically viable), but still a risk to plug. BEst solution is probably just to make balance and allowance 64-bit

Lists are too close to vectors algorithmically

In Clojure, lists are not associative and do not provide random access, unlike vectors.

In Convex, what lists are and their difference from vectors is a bit confusing since you can use assoc and get.

(assoc (list :a :b) 0 :OK)  ;; => '(:OK :b)

(get (list :a :b) 1)  ;; => :b

Furthermore, it muddles the algorithmic difference between get and nth, where get should be about an optimal random access whereas nth is supposedly linear (converting any data structure to a sequence (logical list) and hoping from cell to cell).

Add 'import' statement

Convex should allow 'import' as a statement to create an alias to actor / library code.

Intended usage

(import "adc7f06290972f6aafee38509cf662c42d13dcfed128dc99dc7ceb7414c71062" :as my.library)

(my.library/do-stuff 1 2 3)

Fatal error: destructuring a set

Destructuring a non-sequential value like 42 fails gracefully, but destructuring a set (specifically) results in a fatal error and breaks the executing account.

Screenshot from 2021-04-22 15-00-32

Add PKCS #12 Key Store

Convex should make use of a PKCS #12 key store

Key points:

  • Should work with standard Java Key Store tools
  • Should be protected by default with a decent key phrase
  • Should be stored in the '.convex' directory for the current user on the local machine

EDN: Escaping quotes in `AString`

As reminded by this line (https://github.com/Convex-Dev/convex/blob/master/src/main/java/convex/core/data/AString.java#L17), quotes are not double-escaped when writing EDN.

This means that if a string contains quotes, its output disrupts the whole EDN string which cannot be read back (not accurately at least).

I can PR a simple fix however:

  1. How is it managed API-wise when the result of a transaction is such a string, in JSON? .toString seems to suffer from the same problem. Is it relevant? I cannot find the answer in the codebase but it seems to behave well.

  2. Isn't it a problem at the level of the Reader? For instance, the code example from actor? in core-metadata.doc:

Source file:

(actor? \"1Ba377262D7637068C8a84b732e30d3Ff62bA891\")

After reading the file, Java string, single-escaped quotes become double-escaped:

"\"(actor? \\\"1Ba377262D7637068C8a84b732e30d3Ff62bA891\\\")\""

After feeding to Reader, single-escaped again:

#object[convex.core.data.StringShort 0x1f11cb95 "(actor? \"1Ba377262D7637068C8a84b732e30d3Ff62bA891\")"]

Inconsistent escaping

Related to #53 , I have a hard time understanding how the Reader escapes/unescapes things. For example, trying these in the sandbox (as is) or directly evaling on the CVM (manually escaping since talking to the JVM):

"\\"  ;; Fine
"\""  ;; Fine
"\b" ;; Syntax error
"\n" ;; Syntax error

Either I am confused or there is something to clarify ;)

Doubles starting only with "." create pathological cases

Currently, the Reader accepts doubles that start with a dot:

(= .5 0.5)

While this is acceptable, it creates pathological cases with symbols since they accept dots as valid characters:

'a.5  ;; => Symbol
'+.5  ;; => Double, 0.5

Inconsistent behavior in `inc` and `dec` with NaN and Infinity

Unlike in other languages, those two functions cast NaN and +-Infinity to 0 producing this kind of inconsistent behavior:

(= 1 (inc NaN))  ;;  A

(= NaN (+ 1 NaN))  ;;  B

This is due to the fact that in Java, casting those to long indeed produces 0. Indeed:

(= 0 (long NaN))  ;; Valid by itself, expected on the JVM

However, B is the right way to handle it. Other math functions seem to behave well because they don't cast doubles to longs (they do the opposite if needed), meaning that those special values are left intact and follow proper float arithmetics.

Consider if Blobs should cast to Long

What should happen with:

(long 0xFF) ;; 255?
(long 0x1000) ;; 4096>
(long 0xFFFFFFFFFFFFFFFF) ;; -1?
(long 0xFFFFFFFFFFFFFFFFFF) ;; argument error?

Behaviour is currently undefined, seems to be an issue.

Unexpected error: `pow` with non-numeric args

Calling pow with a non-numeric argument results in a fatal error and breaks the executing account.

Cause: the Core class do not check if arguments are numbers for graceful failure while the RT class does and throws an IllegalArgumentException.

Screenshot from 2021-04-21 19-43-47

Keywords and symbols are limited to 32 chars

Both in literal notation and by using keyword or symbols, anything more than 32 chars is not understood by the CVM (syntax error and cast error respectively).

(count "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")   ;;  => 33

(symbol "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")  ;; => Cast error

'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa  ;; => Syntax error

Is it a design decision?

Literal notation of keywords misbehave with a namespace

Keywords do not support namespaces but providing one in the literal notation (akin to symbols) produces this weird behavor:

(= :foo/bar
    :bar)
    
;; true

Probable cause: According to Mike, the Reader reuses the symbol implementation for keywords and openly discards the namespace.

Using regular symbol for `NaN` creates pathological cases

When it comes to quoting and unquoting, the fact that the litteral notation for NaN is a regular symbol creates that kind of inconsistent behavior:

'[NaN]      ;; => Actually, NaN is a symbol
'[~NaN]    ;; => Ok, NaN is NaN
'#{~NaN}  ;; => For some reason #{(unquote NaN)}

Intuitively, I don't think you can solve this at the level of quoting/unquoting. It might be that NaN and +-Infinity (in the future) should be expressed through a dedicated notation. For instance, Clojure uses ##NaN.

`actor?` accepts non address castable argument

Both actor? and account? should be used with an argument that is castable to an address, as described in their docstring. However, while account? throws when this is not the case, actor? actually accepts all kind of arguments.

Not a huge deal but inconsistent, so preferably both would behave the same (either solution).

Otherwise it might make it slightly harder for beginners to grasp the difference between actor?, account?, and address?.

Consider explicit account creation

Currently it is possible to create an account directly with a transfer. We should consider if this is wise, and perhaps require an explicit create-account operation (which might require a signature for the target account)

Rationale:

  • Prevents mistakes by transferring to non-existent accounts
  • Consistent with token implementations that rely on an existing account to use set-holding
  • Increase transparency on who created accounts

Downsides:

  • Extra complexity when making transfers to new accounts. Can probably be handled by clients?

Staking functions

Need to implement staking functions in the runtime library.

Key operations:

  • Adjust stake (as peer)
  • Delegate stake (as any user / actor)
  • Claim staking rewards

Booleans should not be considered as numbers

In a low-level language like C, booleans are simply integers and can behave as such. However, in a high-level language, this should be unexpected for the sake of type safety. Even Java agrees.

So I strongly argue that the following should be illegal:

(number? true)  ;; => true

(inc true)  ;; => 2

Looking at the implementation of CVMBool.longValue, it looks like it has been designed on purpose. Any rationale?

Cannot coerce maps to sets

Since maps can be coerced to vectors, they should be coercible to sets (matching Clojure behavior by the way). Currently

(vec {:a :b})  ;; => [[:a :b]]

(set {:a :b}) ;; => Cast error

Scrypt - actors deployment and calls

Should be a Scrypt equivalent to call and deploy in Lisp.

Something like:

call actor-address function_name(arg1,arg2)
call actor-address offer 10000 function_name(arg1,arg2)

Scrypt - statement blocks

Should be possible to execute multiple statements in a block:

{
  a();
  1+2;
  f(a);
}

Which should translate to something like:

(do
  (a)
  (+ 1 2)
  (f a))

Probably needs rules:

  • Block which contains zero or more statements
  • a StatementSeparator that matches a semicolon and optional spacing.

Will need to disambiguate from a map literal. Normal maps will have at one or more (odd number) commas as separators, which should be clear. {} might be tricky.

Unexpected error: `actor?` on inexistant account

Testing whether an inexistant account is an actor results in a NullPointerException which breaks the calling account.

Possible cause: no null checking after retrieving an AccountStatus, before calling .isActor on it.

Screenshot_from_2021-04-20_16-38-44

Tail call operation

We should be able to support tail calls on the CVM with a simple trampoline at virtually no excess cost (as we do with halt and rollback.

This should make some recursive algorithms much more practical.

Should probably be explicit (core function?)

Long Strings

Currently Strings are encoded directly as embedded objects.

We need a way to cleanly separate:

  • Short Strings that can be embedded (perhaps up to X bytes or Y chars)
  • Medium Strings that must be represented as Cells
  • Long Strings that require a representation as multiple cells (similar to Blobs)

Perhaps needs a custom AString type that implements CharSequence

Test maximum message sizes

With new embedding changes, there is a risk that some of the large composite objects could have a message size that exceeds the maximum, which would cause many nasty problems

We need to validate the maximum encoding size for every object type.

Suggested strategy:

  • Create sample objects of maximum size
  • Create static final constants listing the expected maximum size
  • Ensure sample object equal expected maximum
  • Add tests for invariants relating size of composite objects to size of embedded objects

Scrypt - higher order functions

It should be possible for function application to be applied repeatedly, so that a function can be returned from another function and immediately applied.

f(a)(b)

Which should be interpreted as ((f a) b) in Convex Lisp.

May require a rule with ZeroOrMore(FunctionParameters) or similar, similar to how we handle InfixExtension.

Improve `import` statement.

Currently we just have a simple import macro:

(import some-address :as alias)

Should extend this and consider:

  • Ability to make multiple imports in one statement?
  • Ability to directly refer to specific symbols (like Clojure's refer)
  • Ability to replace the convex.core default bindings
  • Additional security checks?

Fatal error: destructuring insufficient input with `&`

The following destructuring breaks the executing account:

Screenshot from 2021-04-22 15-09-38

This is due to how the CVM currently handles what we could call "non-terminal &":

(let [[a & b c d e] [1 2 3 4 5 6 7 8]] [a b c d e])

;; => [1 [2 3 4 5] 6 7 8]

This is really tricky, so tricky that it is illegal in Clojure which only tolerates & in a terminal position (ie. [... & binding]).

Char should not be cast to long

Operations like those fail in Clojure which is arguable more coherent. The fact that chars are somewhat numbers look more a leaky abstraction leading to counter-intuitive results (unless one is accustomed to C).

(+ \a 42)  ;; => 139

(inc \a)  ;; => 98

(max42)  ;; => ù

Scrypt - if statement

We should have a custom if statement that mirror Java / JS

if (condition) {
  dosomething();
}

Suggest getting code blocks working first.

Clarify whether `convex.asset/balance` should cast address

Currently convex.asset does:

  (defn balance
    ^{:doc {:description "Return's asset balance for owner.",
            :examples [{:code "(balance asset-address owner)"}]
            :type :function
            :signature [{:params [asset-address owner]}]}}
    [asset-address owner]
    (call (address asset-address) (balance owner)))

Perhaps there should be an explicit cast (balance (address owner)) in the final line? This would allow users to be a bit looser in address formats (can use literal blobs) and mean that the SPI can assume an actual address?

Shouldn't be possible to transfer NFTs to the NFT actor itself

Currently NFT actor seems to accept transfers of NFTs to itself:

(import convex.nft-tokens :as nft)

(call nft (create-token nil nil))
 => 0
(call nft (create-token nil nil))
 => 1
(call nft (create-token nil nil))
 => 2

(asset/balance nft *address*)
 => #{1,2,0}

(asset/transfer nft [nft #{1 2}] nil)

(asset/balance nft *address*)
 => #{0}

Would expect the transfer (penultimate line) to fail?

No support for `Infinity`

Since CVM doubles rely on actual doubles and floating math, it is possible to produce Infinity:

(/ 1 0)   ; => Infinity
(/ -1 0)   ; => -Infinity

Since they are valid results, it should be accessible to the user just like NaN currently is.

Fix: Adding Infinity and -Infinity in Symbols and register them as special symbols in Core.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.