Lisk: Blockchain development in JavaScript
blog.lisk.io
blog.lisk.io
I don't mean to be rude, but that's the worst possible answer you could have given. Security should be your first priority, not an afterthought to popularity. That it isn't tells me everything I need to know about the seriousness of your project.
I don't even know why you need a study for this anyway. Working in a language where it's impossible to mix up strings and numbers, impossible to call a function with the wrong number of arguments etc. leads to less bugs by definition. Do you really need a study to prove you're more productive and your code is more secure in a language where mixing up types is impossible compared to using a language that lets you make that mistake? You can write secure code in assembly if you want but you're just making life hard for yourself.
Types are a trade off. Sometimes, by explicitly defining interfaces and types ad nauseam, you spend more time defining those types and managing those types than you ever would in fixing minor type errors that after all, generally only come from incorrectly calling a function.
I think JS code tends to be simpler than equivalent Java code and in my opinion, the simplicity of JS offsets its lack of explicit types.
"Simplicity is prerequisite for reliability." -Dijkstra
> Types are a trade off. Sometimes, by explicitly defining interfaces and types ad nauseam, you spend more time defining those types and managing those types than you ever would in fixing minor type errors that after all, generally only come from incorrectly calling a function.
I wouldn't agree with that. Issues with string/number conversions, strings being treated like arrays and unexpected undefined/null (these are particularly bad) are common in my experience in JavaScript. Even if they're not particularly common, you really think having to define a few interfaces takes so much time it nullifies the benefit of automatic error checking? Writing an interface is way less effort than writing a test as well, plus you get automatic refactoring tools, autocomplete and automatic error checking in return.
I really can't see why you'd want to give all that up to save a few keystrokes. I've done years of JavaScript after moving from typed languages like OCaml, C++, Java and Coq, and it's horrible trying to write large apps in plain JavaScript without types.
However, I think that in a strongly typed languages like Java, it's more than a few keystrokes. Also, because there's mutable state everywhere buried in Java classes, you get many more logic errors.
At the end of the day, I think simplicity is the best hedge against errors. However, I tend to agree that statically typed, functional languages are probably the best for preventing errors.
Type inference solves the extra typing issue and Java isn't a great example of a strongly typed language. For JavaScript, you can use TypeScript which has type inference and non-null checking. There's also BuckleScript or Reason if you want to code in OCaml so there's practical ways to get this safety in JavaScript.
> At the end of the day, I think simplicity is the best hedge against errors.
You can have static types + simplicity though which is better than just simplicity. Types and immutability constrain the behaviour of your program to make it simpler to reason about.
This is my point really. A misleading study is worse than no study as people use it to back up their points with a false air of legitimacy.
There is no silver bullet, though the article tries to pass off TDD as one. Also he does concede that static types can power tooling that might "feel like they make us more productive".
Disclaimer: I prefer having types but I also think JavaScript is great and don't shy away from using it.
Regarding the article you linked to, I recommend reading the discussion in the comments section (https://medium.com/@oxymor0n/eric-9f4869bb0ecb).
The UC Davis paper, for example, concludes:
"...language design does have a significant, but modest effect on software quality. Most notably, it does appear that strong typing is modestly better than weak typing, and among functional languages, static typing is also somewhat better than dynamic typing.
"This is strong evidence that functional static languages are less error prone than functional dynamic languages … In order to strengthen this assertion we recode the model as above using treatment coding and observe that the Functional-Static-Strong-Managed language class is significantly less defect prone than the Functional-Dynamic-Strong-Managed language class with p = 0.034."
Do you bother folks writing blockchain implementations in C, which is at least as hard to deliver secure code in?
Just curious if you're consistent in your unfair standard or if this is an even more unfair standard than a literal reading of the text.
I wish Etherium had chosen Javascript. It'd have started from a better place.
If you're interested in developing a better language for smart contracts, check out Viper (https://github.com/ethereum/viper). Although development is kind of slow right now because Vitalik is the only one who merges pull requests.
Quite frankly, I think Etherium is a shameless powergrab by a bunch of folks who's sole positive contribution to the medium is growing it.
It's a tribute to the essentially unskilled & uninformed investors and inventors in many parts of the blockchain ecosystem that Eth has been allowed to grow at all. It's a great idea for the owners of Eth and a terrible idea for everyone, everyone, EVERYONE else (except maybe certain classes of miners).
I've got 0 interest in contributing my time to a system that will only be used to extract wealth from other people's good ideas while simultaneously welding them to a release calendar that keeps them at the back of the pack of blockchain software. If I wanted to pitch in with that, zcash is way more competent anyways.
You don't standardize to a platform at the beginning of a boom. You standardize to protocols. And that is, by the way, exactly what every competent programmer is doing; standardizing on the protocols laid out by bitcoin as they develop their own chains and experiment with new, cheaper ways to sustain a digital currency.
* dapps manage real money in real time
* end users aren't able to evaluate the quality of the dapps they entrust their money to
* what could possibly go wrong?
> any script kiddie can write dapps right away without even bothering to study what the risks are and what is happening under the hood
It's not the contract author's responsibility to guarantee that the contract works properly -- they aren't forcing anyone to use it. Any script kiddie SHOULD be able to write a dapp. Most people don't [understand that they don't] understand the complexities our our modern financial system, but we don't require that one has a PhD in order to spend a dollar. A low barrier to entry when dealing with financial transactions is desirable.
> end users aren't able to evaluate the quality of the dapps they entrust their money to
This is entirely not true. Because dapps are publicly audit-able, an end user can evaluate whether or not he/she wishes to participate in a contract based on his/her understanding of the code. Granted, it might take a lot of time to properly learn the language used to build a contract, but this would be true of any language. Even so, if a user does not understand a contract, he/she can choose not to use it.
Writing a dapp is much closer to issuing an exotic cross-asset derivative than it is to spending a dollar.
Correct me if I'm wrong, but I believe that auditing a Dapp is far from trivial. Only the bytecode is stored in the blockchain, and even if the source code is published, it's hard to see if it corresponds to the published bytecode (and even then, FOSS still have bugs, remember OpenSSH and its latest security bugs). From [1]:
> Q: How can I verify that a contract on the blockchain matches the source code?
> A: AFAIK the best way to do this at the moment is to compile the source code again with the exact same compiler version the author used (so this is something that needs to be disclosed) and to compare the bytecode. (Thomas Bertani @ StackExchange)
In addition, in the source code itself a contract programmer could implement "contractual" backdoors... ahem.. loopholes. And you'll have no recourse.
[1] https://ethereum.stackexchange.com/questions/195/how-can-i-v...
I agree, this is not trivial, but as you point out, since only the bytecode is stored in the blockchain, examining it must be only way to know what a contract does.
> In addition, in the source code [...]
Yes, the programmer could implement backdoors, no matter what the language is. As such, the end user should not rely on specific properties of a language to make guarantees as to whether or not it the contract does what they expect. It can help, but it's not foolproof.
My point is that if you invest in a smart contract, it is unreasonable rely on outside entities -- either the person who created the contract or the contract language itself --- to ensure that it will work as expected. As hard as it may be to do, if you can't reasonably understand what's going to happen when you enter into a contract, you shouldn't.
I think that simple market approach works well when customers are able to understand and compare what they are buying (or investing into), but it doesn't work when customers don't have the means to do so. That's why the financial industry is one of those that needs to be heavily regulated. So, no, IMHO having lowering the barrier to entry to write complex financial instruments that can trade hundreds of millions of dollars is a recipe for disaster, not for useful innovation.
Of course I understand that, if you're a libertarian, you're not going to agree :)
JS unsafety comes from its loose rules regarding coercion, bugs that only pop up when they're actually executed (sometimes under very specific conditions), etc.
In systems where the Javascript isn't loaded on demand from a server on every use (like a server written in node.js, or an application built with electron), then that issue doesn't apply.
This does not mean you don't have to deal with security (your case still applies), but at least you get rid of some known bugs in advance.
Personally I'm a huge fan of how Flow or Typescript add a type system on top of Javascript and think anyone writing a >500 line web app would hugely benefit from using one of them.
Oh there sure is - every discussion about programming languages is prone to typing flame wars.
Debian for example has people review everything that goes into the package repositories, has policies about what types of things are allowed, and the history of packages on the repository can be inspected. An app developer couldn't selectively deliver a malicious key-leaking version of an application to an individual user running Debian with the application installed from Debian's repository.
You also have the javascript engine/c compiler to worry about, which can of course also be malicious.
Then you have the OS to worry about.
Then, given all that, you have people pretending to know what they are talking about and stating they take security seriously to worry about. When clearly, all your base are belong to us.
:shrug: Javascript is the one language where for its most popular uses, people download the code from a server on every use, and few if any other languages have that as the popular runtime mechanism.
I'd prefer it if the article were more obvious about the issue being the download-on-run mechanism rather than being titled as if the problem were the language itself.
>You also have the javascript engine/c compiler to worry about, which can of course also be malicious. Then you have the OS to worry about. ...
You could say that in any discussion about security, but I'm not sure it's really useful because it seems the implication is to give up on any security problem because perfection isn't possible.
Exactly. But no one does. Which is why you need to worry about all these guys pretending to know security.
Better to assume you are not secure when you mostly are, than assume you are secure when you definately are not. With baseband processors on mobile, and management engine on x64, all security is currently broken at the hardware level anyway. Major mindset shift needed to fix that.
I tend to think of type systems more as a hindrance myself. I mean, they can certainly help you catch bugs before the code even runs - but which of those bugs would you not catch during the testing phase anyway?
I'm genuinely curious: what types of bugs does a stricter type system catch that a reasonable test suite probably would not?
Note I'm not saying that tests guarantee bug-free code, or that you can't do both. I'm just wondering about which different kinds of bugs you might catch.
Short-answer is yes, and there's been lots of work done to go even further than having static typing and have formal verification for smart-contracts.
>I'm genuinely curious: what types of bugs does a stricter type system catch that a reasonable test suite probably would not?
Not sure what you mean by "reasonable" (is it extensive? testing pathological cases? where do you draw the line?). But type checking at compile time makes your code less inclined to showcase a certain class of bugs that are the byproduct of ambiguity in the language semantics and logical mistake in the programmer writing the code.
And with formal verification you can actually make sure that your logic meets the specs. You can hardly extract stronger correctness guarantees than that!
If that interests you, check out Tezos (https://tezos.com/) and github.com/tezos/tezos. The entire codebase is in OCaml.
It was on the frontpage a while back: https://news.ycombinator.com/item?id=15061029
Yes, I've looked at some of these projects before. And I certainly think it's a good idea to use automated tools to try to prove properties about programs.
But I'm more excited about things like property testing than I am about things like strong type systems. And I'm wondering specifically what is the value they bring.
No offense, but all of the answers I've gotten so far are very vague, and don't really address my question. I don't doubt that strong type systems can catch bugs, I am wondering how their capabilities in catching bugs differ from test suites.
Let me give you an example, say we have a hypothetical language with a strict type system, and we declare a variable to be of type List[Foo]. Then later we use that variable as if it was really of type Foo. That's not gonna work, and a type-checker would catch that at compile-time. But a test suite (that covers the variable access) is going to catch that as well, because the code won't behave as it should.
At which point is a strong type system going to surface a bug that a good test suite would not have? Like, can you give an example?
> Not sure what you mean by "reasonable" (is it extensive? testing pathological cases? where do you draw the line?).
The line is as variable as the strictness of the type system we would compare it to.
I guess one could argue that a type system will force the programmer to satisfy it, while a test suite can be written very sloppily. So maybe there is some kind of signalling value in using these types of languages.
Well, for one they can prove the absence of certain classes of bugs. Buffer overflows, for example. No amount of testing can do that.
Obviously most languages have "escape hatches" to do inherently 'unsafe' things like calling into C, but then at least you know exactly which bits to audit especially rigorously.
> But a test suite (that covers the variable access) is going to catch that as well, because the code won't behave as it should.
How many different List[X], where X != Foo do you need to test with to have the assurance you need? Are those tests that will actually get written? (IME it's pretty rare to see such "negative" tests, but then I mostly work in typed languages where such tests are usually unnecessary...)
There's also the really huge advantage to types that they actually document a machine-checked contract in a way that integrates seamlessly with the language. There's no such consistency in e.g. JS-land. Now, those contracts may be pretty vague (in e.g. Java or C#), but in Haskell for example they include such things as "does this function have any side effects?". That's extremely powerful, but it's hard to appreciate just how powerful until you have experience in those type systems.
EDIT: Also, don't forget that tests also have costs -- they have to be maintained just like the rest of the program, and static types can drastically cut down on the amount of tests you need to write+maintain.
Type systems and test suites are complementary. When a test suite finds a bug, that proves that the program is incorrect for some inputs. When a type system doesn't reject a program, that proves that the program is correct for all inputs.
Which one to use depends on the impact of an error. In the case of a system that controls lots of money, you'll want a guarantee that all inputs lead to a correct balance. That suggests to use a type system.
On the other hand, if you're just writing an app to get data from a website and display it, you can probably afford it if the program doesn't work in some cases. If you can write a generator for realistic input, and check the output, that will give you a probabilistic estimate of correctness.
The main advantage that test suites have over type systems is the kind of properties they can easily check. If you have a test suite that only checks that the output values have the right structure (EDIT: https://news.ycombinator.com/item?id=15137691 points out that part of the Lisk test suite does exactly that), you'd probably benefit even from the C type system. But to formalize the correctness of values, for many programs you'd need a much more powerful type system e.g. using dependent types, that isn't quite so simple to use as writing the equivalent test.
I think a good compromise would be a language that allows you to annotate your types with arbitrary properties, but doesn't complain if it can't type-check them, so long as you write a test. (But it should complain when it can prove that the properties never hold, e.g. using success types, so that you don't waste time writing a test for that.)
> Which one to use depends on the impact of an error. In the case of a system that controls lots of money, you'll want a guarantee that all inputs lead to a correct balance. That suggests to use a type system.
When a test suite passes that proves that the program is correct for a subset of all inputs. But I do not see how the same can be said about a type system.
Types do not usually capture semantics - unless we are talking about something a lot more powerful than what I'm used to seeing in real programming languages.
> I think a good compromise would be a language that allows you to annotate your types with arbitrary properties, but doesn't complain if it can't type-check them, so long as you write a test.
But why do I need types for this? Why can't I just assert the properties outright, writing assertions only in terms of the code interface? It's not the types that tell me what arbitrary properties my code should have!
You are right, I should have specified that the correctness proof only applies to properties actually given in the type system. So for a high-stakes financial application, your types should be strong enough to capture at least elementary arithmetic. This is definitely not something you'd see in a mainstream programming language.
> It's not the types that tell me what arbitrary properties my code should have!
When you give a variable in a program a type, you assert a property for all values that variable will ever take. The converse is also true: for any property you want to express, there is a type system that can encode it. This is called the Curry-Howard correspondence.
Unfortunately, most interesting properties one might want to formalize require either an undecidable type system, or you have to write a bunch of proof code just to convince the type checker that the rest of the code conserves the properties it should. That isn't too different if you'd be doing formal verification for all your code anyway, but it gets annoying when it is enforced everywhere, even when you'd deem it unnecessary otherwise. In that, it is similar to a policy of "unit tests everywhere", which probably catches some bugs, but also leads to lots of boilerplate stating the obvious.
> But I'm more excited about things like property testing than I am about things like strong type systems. And I'm wondering specifically what is the value they bring.
By "property checking" you mean theorem proving.
Static type checkers are theorem provers. More powerful type systems allow more interesting and less intuitive proofs to be written. Sometimes, the type checker is integral to the compiler and is required to run on every build, and sometimes it's an external tool.
In any case, if you're adding annotations to your source code in order for a theorem prover to statically prove certain runtime properties, those annotations constitute a static type system which is type-checked by your theorem prover.
Maybe you don't like even a subset of your theorem prover to run on every build, but if you're in favor of machine-checked proofs of program behavior, you're in favor of static typing.
They allow you to say things like, this function takes in a list of Foo objects, and returns one Foo object. But they don't really let you express whether the object returned is or is not part of the original list, and if it is, that it was chosen according to the right mechanism. That's what tests are for.
Without being able to express the semantics of code, I don't see how you can trust it. There may not be any type mismatches, but there sure can be lots of bad logic in there.
[1]: http://hypothesis.works/articles/what-is-property-based-test...
Edge cases that you do not hit in your test cases.
One could also argue that a distributed computing platform coupled to a money system may not need to be Turing complete. State-of-the art type systems are capable of proving non-trivial properties of code which could be handy in the crypto world.
https://en.wikipedia.org/wiki/SPARK_(programming_language)
That being said, I spent some time with Ada several years ago and did not enjoy the language; very verbose and anal. If the impression is widespread, such a language could end up hurting a blockchain project by drawing less contributors.
Here is one paper of interest https://www.comp.nus.edu.sg/~loiluu/papers/oyente.pdf.
Otherwise you'll still have to work out each type before it becomes "automatic". Which is not entirely dissimilar from working out a test suite.
Just switch today. That's kind of silly to write a whole bunch of untyped code and then move to types. Especially since you can do it over time with TS.
All these tests that something is a string... why not let a compiler do that for you?
https://github.com/LiskHQ/lisk/blob/development/test/api/acc...
Why would it be necessary to use a transaction to turn something on/off securely?
C++ for security? I'm not sure that would make me feel any better
What about WASM? Seems like if we're future thinking "things that can run everywhere" just about any language can be compiled into a web assembly target and used. WASM is supported in most major browsers except IE.
Ethereum uses this concept by translating solidity code into ethereum byte-code, whereas Lisk appears to interpret the JavaScript directly without translation. WASM would be a candidate to replace the byte-code in ethereum, but in order to avoid the impracticality of writing contracts directly in WASM, we'd also need a high-level language from which to compile.
This reason this is a good idea is because one could write contracts in any language for which a WASM compiler exists, but I imagine that could also be done with ethereum byte-code. WASM currently has the '"runs literally everywhere" advantage' here, but it should be simple to create a compiler that translates from solidity to WASM, or even directly from ethereum byte-code itself.
Further, I don't buy in to the '"runs literally everywhere" advantage' for JavaScript because it loses this advantage to any language that can compile to it and this is becoming increasingly true for WASM as well.
That's it? So that's consensus? That's easy!
What's the downside of this?
https://facebook.github.io/immutable-js/
Would you wind up with an Immutalisk?
Sorry, but I just don't agree. Javascript is a popular language, and has an important role to play in frontend development, but for financial transactions and critical contract code, the lack of safety almost guarantees catastrophic bugs and vulnerabilities will be made in production code. Maybe this is fine for hobby projects, but if you are talking about moving billions of dollars around in the real global economy, I don't see it being done safely in Javascript. I like that projects such as Tezos are integrating formal verification of smart contract code, that seems like the right way forward.
I don't see a huge problem using some JS blockchain library for some non-critical application if it somehow added to the end product, but something so highly critical... no thanks.
Except for the part about Tezos. I haven't looked into it.
Buzzwords are buzzwords until implementation is (or isn't) proven useful. Lisk is making an attempt. Let's judge the attempt and the fruits or lack thereof.
Disclaimer: I am not an investor, stakeholder, or employee in Lisk.
That's not to say there aren't plenty of promising projects out there. There absolutely are.
Whatever the definition of unsubstantive is, snarky generic dismissals are certainly included.