Skip to content

Commit

Permalink
Merge pull request #894 from ScorexFoundation/tree-template
Browse files Browse the repository at this point in the history
ErgoTree template
  • Loading branch information
aslesarenko authored Jul 26, 2023
2 parents 7550d6b + ae2d144 commit 1c7b9dc
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 37 deletions.
27 changes: 25 additions & 2 deletions interpreter/shared/src/main/scala/sigmastate/Values.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ import sigmastate.serialization.OpCodes._
import sigmastate.TrivialProp.{FalseProp, TrueProp}
import sigmastate.Values.ErgoTree.substConstants
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.basics.{ProveDHTuple, CryptoConstants}
import sigmastate.basics.{CryptoConstants, ProveDHTuple}
import sigmastate.lang.Terms._
import sigmastate.utxo._
import sigmastate.eval._
import sigmastate.eval.Extensions._
import scalan.util.Extensions.ByteOps
import sigmastate.interpreter.ErgoTreeEvaluator._
import debox.cfor
import scorex.util.encode.Base16
import sigmastate.exceptions.InterpreterException

import scala.language.implicitConversions
import scala.reflect.ClassTag
import sigmastate.lang.CheckingSigmaBuilder._
Expand Down Expand Up @@ -1314,13 +1316,16 @@ object Values {
}

/** Serialized proposition expression of SigmaProp type with
* ConstantPlaceholder nodes instead of Constant nodes
* ConstantPlaceholder nodes not replaced by Constant nodes.
*/
lazy val template: Array[Byte] = {
val r = SigmaSerializer.startReader(bytes)
DefaultSerializer.deserializeHeaderWithTreeBytes(r)._4
}

/** Base16 encoding of `template` bytes. */
def templateHex: String = Base16.encode(template)

/** Get proposition expression from this contract.
* When root.isRight then
* if replaceConstants == false this is the same as `root.right.get`.
Expand Down Expand Up @@ -1496,6 +1501,24 @@ object Values {
*/
def withSegregation(prop: SigmaPropValue): ErgoTree =
withSegregation(DefaultHeader, prop)

/** Deserializes an ErgoTree instance from a hexadecimal string.
*
* @param hex a hexadecimal string representing the serialized ErgoTree
*/
def fromHex(hex: String): ErgoTree = {
val bytes = Base16.decode(hex).get
fromBytes(bytes)
}

/** Deserializes an ErgoTree instance from an array of bytes.
*
* @param bytes an array of bytes representing the serialized ErgoTree
*/
def fromBytes(bytes: Array[Byte]): ErgoTree = {
ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes)
}

}

}
19 changes: 13 additions & 6 deletions sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,19 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit {
}

property("ErgoTree.template") {
val t = new ErgoTree(
16.toByte,
Array(IntConstant(1)),
Right(BoolToSigmaProp(EQ(ConstantPlaceholder(0, SInt), IntConstant(1))))
)
t.template shouldBe ErgoAlgos.decodeUnsafe("d19373000402")
{
val t = new ErgoTree(
16.toByte,
Array(IntConstant(1)),
Right(BoolToSigmaProp(EQ(ConstantPlaceholder(0, SInt), IntConstant(1))))
)
t.template shouldBe ErgoAlgos.decodeUnsafe("d19373000402")
}

{
val t = ErgoTree.fromHex("100604000e000400040005000500d803d601e30004d602e4c6a70408d603e4c6a7050595e67201d804d604b2a5e4720100d605b2db63087204730000d606db6308a7d60799c1a7c17204d1968302019683050193c27204c2a7938c720501730193e4c672040408720293e4c672040505720393e4c67204060ec5a796830201929c998c7205029591b1720673028cb272067303000273047203720792720773057202")
t.templateHex shouldBe "d803d601e30004d602e4c6a70408d603e4c6a7050595e67201d804d604b2a5e4720100d605b2db63087204730000d606db6308a7d60799c1a7c17204d1968302019683050193c27204c2a7938c720501730193e4c672040408720293e4c672040505720393e4c67204060ec5a796830201929c998c7205029591b1720673028cb272067303000273047203720792720773057202"
}
}

property("ErgoTree.bytes") {
Expand Down
17 changes: 11 additions & 6 deletions sdk/js/src/main/scala/org/ergoplatform/sdk/js/ErgoTree.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ class ErgoTree(tree: Values.ErgoTree) extends js.Object {
/** Serializes the ErgoTree instance to a hexadecimal string. */
def toHex(): String = tree.bytesHex

/** Serialized proposition expression of SigmaProp type with
* ConstantPlaceholder nodes not replaced by Constant nodes.
*/
def template(): Array[Byte] = tree.template

/** Base16 encoding of `template` bytes. */
def templateHex(): String = tree.templateHex

/** Returns segregated constants of this tree as [[js.Array]]. */
def constants(): js.Array[Value] = {
val constants = tree.constants
Expand All @@ -42,17 +50,14 @@ object ErgoTree extends js.Object {
*
* @param hex a hexadecimal string representing the serialized ErgoTree
*/
def fromHex(hex: String): ErgoTree = {
val bytes = Base16.decode(hex).get
fromBytes(bytes)
}
def fromHex(hex: String): ErgoTree =
new ErgoTree(Values.ErgoTree.fromHex(hex))

/** Deserializes an ErgoTree instance from an array of bytes.
*
* @param bytes an array of bytes representing the serialized ErgoTree
*/
def fromBytes(bytes: Array[Byte]): ErgoTree = {
val tree = ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes)
new ErgoTree(tree)
new ErgoTree(Values.ErgoTree.fromBytes(bytes))
}
}
17 changes: 6 additions & 11 deletions sigma-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,22 @@ The modules published here can be used directly from JavaScript.

# Getting Started

Add the following dependency to your `package.json`:

```json
{
"dependencies": {
"sigmastate-js": "0.1.1"
}
}
Run following command to add Sigma.JS as a project dependency:

```bash
npm install sigmastate-js
```
Then run `npm install`.

# Examples

### How to create Sigma type descriptors

Import `TypeObj` module, then use:

- fields to create simple types (e.g. `TypeObj.Int`)
- method `TypeObj.pairType` (e.g. `TypeObj.pairType(TypeObj.Int, TypeObj.Long)`)
- method `TypeObj.collType` (e.g. `TypeObj.collType(TypeObj.Int)`)

See examples in tests [Type.spec.js](https://github.com/ScorexFoundation/sigmastate-interpreter/blob/933acd7a3753725c8b41994c2126a20279b6809b/sigma-js/tests/js/Type.spec.js)

### How to create Sigma values
Expand All @@ -51,4 +47,3 @@ See examples in tests [ErgoTree.spec.js](https://github.com/ScorexFoundation/sig

Import `SigmaCompilerObj` module and `SigmaCompiler` class, then use its methods.
See compiler tests in [SigmaCompiler.spec.js](https://github.com/ScorexFoundation/sigmastate-interpreter/blob/933acd7a3753725c8b41994c2126a20279b6809b/sigma-js/tests/js/SigmaCompiler.spec.js)

7 changes: 4 additions & 3 deletions sigma-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
"name": "sigmastate-js",
"version": "0.2.1",
"description": "Sigma.js library",
"main": "dist/main.js",
"files": [
"dist/",
"sigmastate-js.d.ts",
"README.md"
],
"types": "./sigmastate-js.d.ts",
"exports": {
"./internal-*": null,
"./*": "./dist/*.js"
"./main": {
"types": "./sigmastate-js.d.ts",
"default": "./dist/main.js"
}
},
"license": "MIT",
"publishConfig": {
Expand Down
21 changes: 12 additions & 9 deletions sigma-js/sigmastate-js.d.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
declare module "sigmastate-js/main" {
type SigmaCompilerNamedConstantsMap = { [key: string]: Value };
type HexString = string;
type ByteArray = { u: Int8Array };

class ErgoTree {
export declare class ErgoTree {
toHex(): HexString;
bytes(): { u: Uint8Array };
bytes(): ByteArray;
header(): number;
version(): number;
isConstantSegregation(): boolean;
hasSize(): boolean;
constants(): Value[];
template(): ByteArray;
templateHex(): HexString;
toString(): string;
}

class ErgoTreeObj {
export declare class ErgoTreeObj {
static fromHex(value: HexString): ErgoTree;
}

class Type {
export declare class Type {
name: string;
toString(): string;
}

class TypeObj {
export declare class TypeObj {
static Byte: Type;
static Short: Type;
static Int: Type;
Expand All @@ -40,13 +43,13 @@ declare module "sigmastate-js/main" {
static collType(elemType: Type): Type;
}

class Value<T = unknown> {
export declare class Value<T = unknown> {
data: T;
tpe: Type;
toHex(): HexString;
}

class ValueObj {
export declare class ValueObj {
static ofByte(value: number): Value<number>;
static ofShort(value: number): Value<number>;
static ofInt(value: number): Value<number>;
Expand All @@ -57,7 +60,7 @@ declare module "sigmastate-js/main" {
static fromHex<T>(hex: HexString): Value<T>;
}

class SigmaCompiler {
export declare class SigmaCompiler {
compile(
namedConstants: SigmaCompilerNamedConstantsMap,
segregateConstants: boolean,
Expand All @@ -66,7 +69,7 @@ declare module "sigmastate-js/main" {
): ErgoTree;
}

class SigmaCompilerObj {
export declare class SigmaCompilerObj {
static forMainnet(): SigmaCompiler;
static forTestnet(): SigmaCompiler;
}
Expand Down
6 changes: 6 additions & 0 deletions sigma-js/tests/js/ErgoTree.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,11 @@ describe("Smoke tests for ErgoTree", () => {
let constants = tree.constants().map(c => c.toHex())
expect(constants).toEqual(["0400", "0e00", "0400", "0400", "0500", "0500"])
});

it("Has template", () => {
let tree = ErgoTreeObj.fromHex(hex);
let templateHex = tree.templateHex();
expect(templateHex).toEqual("d803d601e30004d602e4c6a70408d603e4c6a7050595e67201d804d604b2a5e4720100d605b2db63087204730000d606db6308a7d60799c1a7c17204d1968302019683050193c27204c2a7938c720501730193e4c672040408720293e4c672040505720393e4c67204060ec5a796830201929c998c7205029591b1720673028cb272067303000273047203720792720773057202")
});
});

0 comments on commit 1c7b9dc

Please sign in to comment.