Skip to content

Commit

Permalink
Merge pull request #89 from ergoplatform/develop
Browse files Browse the repository at this point in the history
Release v4.0.5 (with Sigma v4.0.3 and ergo-wallet v4.0.12)
  • Loading branch information
aslesarenko authored Jun 15, 2021
2 parents db0be9f + 6726112 commit da11a26
Show file tree
Hide file tree
Showing 14 changed files with 343 additions and 75 deletions.
130 changes: 76 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Appkit: A Library for Polyglot Development of Ergo Applications

**NOTE: The code in Appkit is experimental. All APIs may change and/or
be removed without notice.**

## Contents
- [Introduction](#introduction)
- [Using from Java](#using-from-java)
Expand All @@ -12,26 +9,33 @@ be removed without notice.**
- [Prerequisites](#prerequisites)
- [Install GraalVM Community Edition on MacOS](#install-graalvm-community-edition-on-macos)
- [Building the Appkit jar file](#building-the-appkit-jar-file)
- [Why Polyglot](#why-polyglot)
- [Why Polyglot](#how-graalvm-can-be-used)
- [Projects that use Appkit](#projects-that-use-appkit)

## Introduction
[Ergo](https://ergoplatform.org/en/) is a resilient blockchain platform for
contractual money. In addition to [Bitcoin](https://bitcoin.org/en/)-like
blockchain architecture Ergo provides advanced contractual capabilities, which
are not possible in Bitcoin.
blockchain architecture Ergo provides advanced contractual capabilities based on
eUTXO model, which are not possible in Bitcoin.

Because of these capabilities numerous decentralized applications become
possible(see [ErgoScript](https://ergoplatform.org/docs/ErgoScript.pdf),
possible (see also [ErgoScript](https://ergoplatform.org/docs/ErgoScript.pdf) and
[Advanced ErgoScript
examples](https://ergoplatform.org/docs/AdvancedErgoScriptTutorial.pdf),
[CrowdFunding](https://ergoplatform.org/en/blog/2019_09_06_crowdfund/),
[Auctions On Ergo](https://www.ergoforum.org/t/auctions-on-ergo/122),
[Interest-Free Loan
Contract](https://www.ergoforum.org/t/interest-free-loan-contract/67) etc). Ergo
applications can avoid centralization of trust and instead rely on trust-less
truly decentralized protocols which are implemented using Ergo contracts
deployed on Ergo blockchain.
examples](https://ergoplatform.org/docs/AdvancedErgoScriptTutorial.pdf)):
- [SigmaUSD](https://sigmausd.io/) - the first UTxO-based stable coin.
- [ErgoMixer](https://github.com/ergoMixer/ergoMixBack) - The first working
non-custodial, programmable, non-interactive mixer in the cryptocurrency space.
- [ErgoAuctions](https://ergoauctions.org) - a decentralized auction house,
secure and easy to use. A simple way to sell or buy Ergo's tokens, artworks,
NFTs, etc.
- [ErgoDex](https://ergodex.io/) - Decentralized exchange on Ergo and Cardano
- [CrowdFunding](https://ergoplatform.org/en/blog/2019_09_06_crowdfund/) - a way of raising capital through the collective efforts of individuals
- [Interest-Free Loan
Contract](https://www.ergoforum.org/t/interest-free-loan-contract/67) etc.

Ergo Applications can avoid centralization of trust and instead rely on
trust-less truly decentralized protocols which are implemented using Ergo
contracts deployed on Ergo blockchain.

By its very nature, Ergo applications are both decentralized and cross-platform
ranging from web applications running in browsers, mobile applications running
Expand All @@ -41,16 +45,19 @@ to services deployed in cloud servers.
That said, it is very desirable to provide consistent programming model and APIs
to facilitate all those application scenarios and platforms.

Appkit library is based on [GraalVM](https://www.graalvm.org) - a novel next
generation approach to implement software which is reusable across several
programming languages and execution environments (see [motivation for using
Graal](#why-graal) below).

Appkit has idiomatic Java API and is written in Java/Scala. It is a thin wrapper
around core components provided by [ErgoScript
Ergo Appkit has idiomatic Java API and is written in Java/Scala. It is a thin
wrapper around core components provided by [ErgoScript
interpreter](https://github.com/ScorexFoundation/sigmastate-interpreter) and
[Ergo protocol](https://github.com/ergoplatform/ergo) implementations which are
written in Scala.
written in Scala. It is
[published](https://mvnrepository.com/artifact/org.ergoplatform/ergo-appkit) on
maven repository and cross compiled to both Java 7 and Java 8+ jars.

The Appkit library is compatible with [GraalVM](https://www.graalvm.org) - a
novel next generation approach to implement software which is reusable across
several programming languages and execution environments. For example if Node.js
application is run on GraalVM, then it can use Appkit to interact with Ergo
Blockchain (see [motivation for using Graal](#why-graal) below).

Using Appkit Ergo applications can be written in one of the languages supported
by GraalVM (i.e. Java, JavaScript, C/C++, Python, Ruby, R) and using this
Expand All @@ -59,7 +66,9 @@ programming model provided by Appkit. In addition Appkit based Ergo applications
can be compiled into native code using [native-image ahead of time
compiler](https://www.graalvm.org/docs/reference-manual/native-image/) and then
executed without Java VM with very fast startup time and lower runtime memory
overhead compared to a Java VM.
overhead compared to a Java VM. For example this allows to create very
responsive command line utility applications such as
[ergo-tool](https://github.com/ergoplatform/ergo-tool).

Please follow the [setup instructions](#setup) to get started.

Expand All @@ -68,40 +77,48 @@ Please follow the [setup instructions](#setup) to get started.
### Using from Java

Among other things, Appkit library allows to communicate with Ergo nodes via
REST API. Let's see how we can write ErgoTool - a simple Java console application (similar to
[REST API](https://github.com/ergoplatform/ergo/blob/master/src/main/resources/api/openapi.yaml).
Let's see how we can write ErgoTool - a simple Java console application (similar to
[ergo-tool](https://github.com/ergoplatform/ergo-tool) utility)
which uses Appkit library. ErgoTool allows to create and send a new transaction
to an Ergo node which, for example, can be started locally and thus available at
`http://localhost:9052/`. Suppose we [set up a full
to an any existing Ergo node on the network which. A new node can also be started
locally and thus available at `http://localhost:9052/`. Suppose we [set up a full
node](https://github.com/ergoplatform/ergo/wiki/Set-up-a-full-node) and started
it using the following command.
```shell
$ java -jar -Xmx4G target/scala-2.12/ergo-4.0.8.jar --testnet -c ergo-testnet.conf
```

We will need some configuration parameters which can be loaded from
`ergotool.json` file which looks like this
[ergotool.json](ergotool.json) file which looks like this
```json
{
"node": {
"nodeApi": {
"apiUrl": "http://localhost:9051/",
"apiUrl": "http://139.59.29.87:9053",
"apiKey": "82344a18c24adc42b78f52c58facfdf19c8cc38858a5f22e68070959499076e1"
},
"wallet": {
"mnemonic": "slow silly start wash bundle suffer bulb ancient height spin express remind today effort helmet",
"password": "",
"mnemonicPassword": ""
},
"networkType": "TESTNET"
"networkType": "MAINNET"
},
"parameters": {
"newBoxSpendingDelay": "30"
}
}
```

Here `apiKey` is the secret key required for API authentication which can be
obtained as described
[here](https://github.com/ergoplatform/ergo/wiki/Ergo-REST-API#setting-an-api-key).
And mnemonic is the secret phrase obtained during [setup of a new
wallet](https://github.com/ergoplatform/ergo/wiki/Wallet-documentation).
wallet](https://github.com/ergoplatform/ergo/wiki/Wallet-documentation) or if
you don't want to setup your node using ergo-tool's
[mnemonic](https://github.com/ergoplatform/ergo-tool#supported-commands)
command.

Our example app also reads the amount of NanoErg to put into a new box from command line arguments
```java
Expand Down Expand Up @@ -164,7 +181,7 @@ that box.

```java
// the only way to create transaction is using builder obtained from the context
// the builder keeps relationship with the context to access nessary blockchain data.
// the builder keeps relationship with the context to access necessary blockchain data.
UnsignedTransactionBuilder txB = ctx.newTxBuilder();

// create new box using new builder obtained from the transaction builder
Expand All @@ -185,16 +202,16 @@ If no such constants are used, then `ConstantsBuilder.empty()` can be passed.

In this specific case we pass public key of the `prover` for `pkOwner`
placeholder of the script meaning the box can be spend only by the owner of the
Ergo node we are working with.
public key from the `wallet` section of [ergotool.json](ergotool.json).

Next create an unsigned transaction using all the data collected so far.
Next we create an unsigned transaction using all the data collected so far.
```java
// tell transaction builder which boxes we are going to spend, which outputs
// to create, amount of transaction fees and address for change coins.
UnsignedTransaction tx = txB.boxesToSpend(boxes.get())
.outputs(newBox)
.fee(Parameters.MinFee)
.sendChangeTo(prover.getP2PKAddress())
.sendChangeTo(prover.getP2PKAddress()) // i.e. back to the wallet's pk
.build();
```

Expand All @@ -206,7 +223,7 @@ is not really used here.
```java
SignedTransaction signed = prover.sign(tx);
String txId = ctx.sendTransaction(signed);
return signed.toJson(true);
return signed.toJson(/*prettyPrint=*/true, /*formatJson=*/true);
```
As the last step we serialize signed transaction into Json with turned on pretty
printing. Please see the [full source
Expand All @@ -215,7 +232,8 @@ example.

## Using from other languages
In additiona to Java, Appkit can be used to write Ergo applications in Scala, JavaScript,
Python and Ruby and run those applications under GraalVM.
Python and Ruby and run those applications under GraalVM, which support cross
language interoperability.
Please see [examples](https://github.com/aslesarenko/ergo-appkit-examples).

## Repository organization
Expand Down Expand Up @@ -247,8 +265,8 @@ edition should be enough for Ergo Appkit library.

First you need to download an archive with the [latest
release](https://github.com/oracle/graal/releases) of GraalVM (e.g.
`graalvm-ce-darwin-amd64-19.2.1.tar.gz`) for MacOS and put the programs from it
onto the `$PATH`.
`graalvm-ce-darwin-amd64-19.2.1.tar.gz` at the time of writing) for MacOS and
put the programs from it onto the `$PATH`.

```shell
$ cd <your/directory/with/downloaded/graal>
Expand Down Expand Up @@ -279,16 +297,18 @@ GraalVM JavaScript (GraalVM CE Native 19.2.1)

### Building the Appkit jar file

At the moment Appkit is not published at public servers, so the whole repository
needs to be clonned and Appkit jar file published locally in the Ivy repository.
Appkit is
[published](https://mvnrepository.com/artifact/org.ergoplatform/ergo-appkit),
however, you can clone the whole repository build it and published locally in
the Ivy repository.

```shell
$ git clone https://github.com/ergoplatform/ergo-appkit.git
$ cd ergo-appkit
$ sbt publishLocal
```

## Why Polyglot?
## How GraalVM can be used?

After many years of research and development GraalVM project has matured enough end
became [production ready](https://medium.com/graalvm/announcing-graalvm-19-4590cf354df8).
Expand All @@ -314,8 +334,9 @@ languages.

- All the code from [ErgoScript
interpreter](https://github.com/ScorexFoundation/sigmastate-interpreter/pulls),
[ergo-wallet](https://github.com/ergoplatform/ergo-wallet) and this Appkit is compatible with
`native-image` and can be compiled into either native application or shared library.
[ergo-wallet](https://github.com/ergoplatform/ergo-wallet) and this Appkit
library is compatible with `native-image` and can be compiled into either native
application or shared library.

- Appkit API interfaces can be used from JavaScript and Python by design. They
can also be [used from C/C++](https://github.com/aslesarenko/ergo-appkit-examples/tree/master/c-examples) .
Expand All @@ -329,14 +350,15 @@ overhead when running scripts
## Projects that use Appkit

Appkit is a foundational non-opinionated libarary which can be used to create other
libraries, Apps and tools. Here is the list of project which are using Appkit.

- [ergo-tool](https://github.com/ergoplatform/ergo-tool)
- [ergo-appkit-examples](https://github.com/aslesarenko/ergo-appkit-examples)
- [ergo-android](https://github.com/aslesarenko/ergo-android)
- [ErgoMixer](https://github.com/ergoMixer/ergoMixBack)
- [ergo-playgrounds](https://github.com/ergoplatform/ergo-playgrounds)
- [Gravity-Ergo-Proxy](https://github.com/mhssamadani/Gravity-Ergo-Proxy)
- [Kiosk](https://github.com/scalahub/Kiosk)
- [ergo-mixer-demo](https://github.com/anon92048/ergo-mixer-demo)
libraries, Apps and tools. Here is the list of projects which use Appkit.

- [ergo-tool](https://github.com/ergoplatform/ergo-tool) - a Command Line Interface application for Ergo
- [ergo-appkit-examples](https://github.com/aslesarenko/ergo-appkit-examples) - Ergo Appkit Examples
- [ergo-android](https://github.com/aslesarenko/ergo-android) - Example Android application
- [ErgoMixer](https://github.com/ergoMixer/ergoMixBack) - a web application for mixing ergs and tokens based on Ergo platform
- [ergo-playgrounds](https://github.com/ergoplatform/ergo-playgrounds) - Run contracts + off-chain code in the browser
- [Gravity-Ergo-Proxy](https://github.com/mhssamadani/Gravity-Ergo-Proxy) - Wrapper of Ergo Node to work with Gravity.tech
- [ergo-jde](https://github.com/ergoplatform/ergo-jde) - JSON dApp Environment (JDE)
- [Kiosk](https://github.com/scalahub/Kiosk) - a library on top of Ergo-Appkit for interacting with the Ergo Blockchain
- [ergo-mixer-demo](https://github.com/anon92048/ergo-mixer-demo) - a non-interactive (and non-custodial) mixing scheme on top of the Ergo Platform blockchain
- Add your project here by creating a PR
11 changes: 10 additions & 1 deletion appkit/src/test/scala/org/ergoplatform/appkit/AddressSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,22 @@ class AddressSpec extends PropSpec with Matchers with ScalaCheckDrivenPropertyCh
}

property("Address fromMnemonic") {
val mnemonic = SecretString.create("slow silly start wash bundle suffer bulb ancient height spin express remind today effort helmet")
val addr = Address.fromMnemonic(NetworkType.TESTNET, mnemonic, SecretString.empty())
addr.toString shouldBe addrStr
val addr2 = Address.fromMnemonic(NetworkType.MAINNET, mnemonic, SecretString.empty())
addr2.toString shouldNot be (addrStr)
}

property("Address createEip3Address") {
val addr = Address.fromMnemonic(NetworkType.MAINNET, mnemonic, SecretString.empty())
val firstEip3Addr = Address.createEip3Address(0, NetworkType.MAINNET, mnemonic, SecretString.empty())
firstEip3Addr.toString shouldBe firstEip3AddrStr
addr.toString shouldNot be (firstEip3AddrStr)

val secondEip3Addr = Address.createEip3Address(1, NetworkType.MAINNET, mnemonic, SecretString.empty())
secondEip3Addr.toString shouldBe secondEip3AddrStr
}

property("create Address from ErgoTree with DHT") {
val tree = "100207036ba5cfbc03ea2471fdf02737f64dbcd58c34461a7ec1e586dcd713dacbf89a120400d805d601db6a01ddd6027300d603b2a5730100d604e4c672030407d605e4c672030507eb02ce7201720272047205ce7201720472027205"
implicit val encoder: ErgoAddressEncoder = ErgoAddressEncoder.apply(NetworkType.MAINNET.networkPrefix);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ object DhtUtils {
| proveDHTuple(groupGenerator, g_y, g_x, g_xy) // for alice
|}""".stripMargin);

val dhtBoxCreationTx = putToContractTx(ctx, sender, contract, amountToSend)
val dhtBoxCreationTx = putToContractTx(ctx, sender, false, contract, amountToSend)
dhtBoxCreationTx
}

Expand Down
77 changes: 77 additions & 0 deletions appkit/src/test/scala/org/ergoplatform/appkit/TxBuilderSpec.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ergoplatform.appkit

import java.io.File
import java.math.BigInteger
import java.util.Arrays

Expand Down Expand Up @@ -148,4 +149,80 @@ class TxBuilderSpec extends PropSpec with Matchers
signed.getOutputsToSpend.size() shouldBe 2
}
}

property("ErgoProverBuilder.withEip3Secret require mnemonic") {
val ergoClient = createMockedErgoClient(MockData(Nil, Nil))
assertExceptionThrown(
ergoClient.execute { ctx: BlockchainContext =>
ctx.newProverBuilder()
.withEip3Secret(0)
.build()
},
exceptionLike[IllegalArgumentException](
"Mnemonic is not specified, use withMnemonic method.")
)
}

property("ErgoProverBuilder.withEip3Secret check uniqueness of derivation index") {
val ergoClient = createMockedErgoClient(MockData(Nil, Nil))
assertExceptionThrown(
ergoClient.execute { ctx: BlockchainContext =>
ctx.newProverBuilder()
.withMnemonic(mnemonic, SecretString.empty())
.withEip3Secret(0)
.withEip3Secret(0) // attempt to add the same index
.build()
},
exceptionLike[IllegalArgumentException](
"Secret key for derivation index 0 has already been added.")
)
}

private def testEip3Address(ctx: BlockchainContext, index: Int): Address = {
Address.createEip3Address(index, ctx.getNetworkType,
mnemonic, SecretString.empty())
}

property("ErgoProverBuilder.withEip3Secret should pass secrets to the prover") {
val ergoClient = createMockedErgoClient(MockData(Nil, Nil))
ergoClient.execute { ctx: BlockchainContext =>
val prover = ctx.newProverBuilder()
.withMnemonic(mnemonic, SecretString.empty())
.withEip3Secret(0)
.withEip3Secret(1)
.build()
assert(prover.getEip3Addresses.size() == 2)
assert(prover.getEip3Addresses.get(0) == testEip3Address(ctx, 0))
assert(prover.getEip3Addresses.get(1) == testEip3Address(ctx, 1))
}
}

property("send to recipient (non EIP-3)") {
val data = MockData(
Seq(
loadNodeResponse("response_Box1.json"),
loadNodeResponse("response_Box2.json"),
loadNodeResponse("response_Box3.json"),
"21f84cf457802e66fb5930fb5d45fbe955933dc16a72089bf8980797f24e2fa1"),
Seq(
loadExplorerResponse("response_boxesByAddressUnspent.json")))

val ergoClient = createMockedErgoClient(data)

ergoClient.execute { ctx: BlockchainContext =>
val senderProver = BoxOperations.createProver(ctx,
new File("storage/E2.json").getPath, "abc")
.withEip3Secret(0)
.withEip3Secret(1)
.build

val recipient = senderProver.getEip3Addresses.get(1)
val amountToSend = 1000000
val pkContract = ErgoContracts.sendToPK(ctx, recipient)
val signed = BoxOperations.putToContractTx(ctx,
senderProver, false, pkContract, amountToSend)
assert(signed != null)
}
}

}
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ assemblyMergeStrategy in assembly := {
lazy val allConfigDependency = "compile->compile;test->test"

val sigmaStateVersion = "4.0.3"
val ergoWalletVersion = "4.0.11"
val ergoWalletVersion = "4.0.12"
lazy val sigmaState = ("org.scorexfoundation" %% "sigma-state" % sigmaStateVersion).force()
.exclude("ch.qos.logback", "logback-classic")
.exclude("org.scorexfoundation", "scrypto")
Expand Down
Loading

0 comments on commit da11a26

Please sign in to comment.