diff --git a/interpreter/shared/src/main/scala/sigmastate/Values.scala b/interpreter/shared/src/main/scala/sigmastate/Values.scala index c2b6de9823..1e9114a782 100644 --- a/interpreter/shared/src/main/scala/sigmastate/Values.scala +++ b/interpreter/shared/src/main/scala/sigmastate/Values.scala @@ -15,7 +15,7 @@ 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._ @@ -23,7 +23,9 @@ 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._ @@ -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`. @@ -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) + } + } } diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala index d76f54e6e8..20aabb1b00 100644 --- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -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") { diff --git a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ErgoTree.scala b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ErgoTree.scala index 672f79e687..810cc1ea81 100644 --- a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ErgoTree.scala +++ b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/ErgoTree.scala @@ -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 @@ -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)) } } diff --git a/sigma-js/README.md b/sigma-js/README.md index 22975e60cd..1531088cbd 100644 --- a/sigma-js/README.md +++ b/sigma-js/README.md @@ -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 @@ -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) - diff --git a/sigma-js/package.json b/sigma-js/package.json index 1e65230766..b1ff6c4df7 100644 --- a/sigma-js/package.json +++ b/sigma-js/package.json @@ -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": { diff --git a/sigma-js/sigmastate-js.d.ts b/sigma-js/sigmastate-js.d.ts index 9351297677..04bc1c7f49 100644 --- a/sigma-js/sigmastate-js.d.ts +++ b/sigma-js/sigmastate-js.d.ts @@ -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; @@ -40,13 +43,13 @@ declare module "sigmastate-js/main" { static collType(elemType: Type): Type; } - class Value { + export declare class Value { data: T; tpe: Type; toHex(): HexString; } - class ValueObj { + export declare class ValueObj { static ofByte(value: number): Value; static ofShort(value: number): Value; static ofInt(value: number): Value; @@ -57,7 +60,7 @@ declare module "sigmastate-js/main" { static fromHex(hex: HexString): Value; } - class SigmaCompiler { + export declare class SigmaCompiler { compile( namedConstants: SigmaCompilerNamedConstantsMap, segregateConstants: boolean, @@ -66,7 +69,7 @@ declare module "sigmastate-js/main" { ): ErgoTree; } - class SigmaCompilerObj { + export declare class SigmaCompilerObj { static forMainnet(): SigmaCompiler; static forTestnet(): SigmaCompiler; } diff --git a/sigma-js/tests/js/ErgoTree.spec.js b/sigma-js/tests/js/ErgoTree.spec.js index f951b2ea99..688ea9bfa3 100644 --- a/sigma-js/tests/js/ErgoTree.spec.js +++ b/sigma-js/tests/js/ErgoTree.spec.js @@ -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") + }); });