- Author: aslesarenko
- Status: Proposed
- Created: 06-Apr-2020
- License: CC0
- Forking: not needed
- Description
- Background And Motivation
- Example Use Cases
- Contract Template Serialization Format
- Parameter Serialization Format
- JSON Format
- Conversion to ErgoTree
- Notes on Supporting this EIP in ErgoTree Compilers
This EIP defines a standard serialization formats and contract metadata for cross-platform reusable contract templates.
Ergo supports flexible language ErgoTree of guarding propositions which protect UTXO boxes. The propositions are stored in the blockchain according to ErgoTree serialization format, which is designed for compact storage and fast script execution and transaction validation.
However, ErgoTree binary format intentionally doesn't include metadata, which may be necessary for various Ergo applications.
This standard defines extended serialization format of contract templates, which may be reused across different protocol implementations, applications and tools on many execution environments.
- ErgoTree compilers can generate contract templates with the necessary metadata
- The template generated by ErgoScala compiler can be used in the environments where Java jar library generated by Scala2.12 is not supported (Android, native, web, etc.)
- Once generated the contract template becomes self-contained and can be stored, transfered, parsed, executed etc across platforms, tools and applications.
- The contract template format supports partial ErgoTree implementations.
Each contract template can be represented using an array of bytes. The content of the array is the following sequence of data fields. Note, the Field Name is not saved and used here only for description of the corresponding content. Thus, the format is schema-less. Binary serialization format is suitable for compact storage and wire transfers. All the fields are required (mandatory).
Field Name | Format | Example | Description |
---|---|---|---|
TreeVersion |
Opt[UByte] |
1 | Optional version of ErgoTree which should be used |
NameLength |
VLQ(UInt) |
18 | Length of Name bytes (> 0) |
Name |
Bytes |
"rewardOutputScript" | User readable name (non-empty string bytes in UTF-8 encoding) |
DescLength |
VLQ(UInt) |
20 | Length of Description bytes (>= 0) |
Description |
Bytes |
"holds mining rewards" | User readable contract description (string bytes in UTF-8 encoding) |
ConstNum |
VLQ(UInt) |
2 | Number of items in ConstTypes and ConstValues (>= 0) |
ConstTypes |
Type* |
(*) | ConstNum of constant types serialized (see Type Serialization section of ErgoTree Spec |
ConstValues |
Opt[Opt[Data]*] |
(**) | Optional. Either None or ConstNum number of again optional default constant values serialized (see Data Serialization section of ErgoTree Spec) |
ParamNum |
VLQ(UInt) |
1 | Number of named template parameters (>= 0) |
Parameters |
Parameter* |
minerPk: SigmaProp | Typed template parameters (see Parameter Serialization Format section below) |
TemplateSize |
VLQ(UInt) |
28 | Size in bytes of the serialized ExpressionTree field (> 0) |
ExpressionTree |
Expr |
(***) | Contract Template expression bytes with ConstantPlaceholders (see Expression Serialization section of ErgoTree Spec |
Notes:
-
In general, some constants are required which depends on the contract semantics. The format doesn't impose any restrictions on that. Some constant values like
720
take small number of bytes, but others, like SigmaProp in the example, are even larger than the template bytes itself (compare(**)
and(***)
hex). Constants that are not required can be omitted. -
The format is optimized for the size of the serialized bytes. For this purpose
ConstValues
field is separated from theConstTypes
field and each constant value is serialized as Data format prefixed by 0 - if the value isNone
, and 1 - if the value isSome(v)
. Thev
bytes follow immediately after the Some prefix. Thus, large constants can be omitted. -
Some contracts may have
ExpressionTree
field where all semantically significant constants are not segregated. In most cases this is more compact and can be done by the compilers (e.g. ErgoScala compiler) where constant <-> parameter mapping is explicit. For such contracts the wholeConstValues
field may be serialized as None. -
TemplateSize
field can be used to skip parsingExpressionTree
when the contract template is embedded into some other format. Thus, templates can be quickly scanned and theExpressionTree
bytes can be obtained for hashing or template-based requests to the blockchain. -
each ContractTemplate can be converted to ErgoTree of the corresponding version (using
t.TreeVersion
)0
(*) IR:
Seq(
SInt,
SSigmaProp
)
Hex: "0x0408"
(**) IR:
Seq(
720,
SigmaProp(ProveDlog(ECPoint(79be66, 483ada,...)))
)
Hex: "0x0101a00b01cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
(***) IR:
SigmaAnd(Seq(
BoolToSigmaProp(GE(Height,Plus(SelectField(ExtractCreationInfo(Self),1), ConstantPlaceholder(0,SInt)))),
ConstantPlaceholder(1,SSigmaProp)))
)
Hex: "0xea02d192a39a8cc7a70173007301"
Parameters specify additional meta information for the contract template. The number of
parameters can be less then or equal to the number of segregated constants (see ConstNum
field). This is because some constant values may not be changed without breaking contract
logic and hence they cannot be used as template parameters. This depends on the contract,
the format supports all the necessary combinations.
Field Name | Format | Example | Description |
---|---|---|---|
NameLength |
VLQ(UInt) |
7 | Length of Name bytes |
Name |
Bytes |
"minerPk" | User readable parameter name (string bytes in UTF-8 encoding) |
DescLength |
VLQ(UInt) |
18 | Length of Description bytes |
Description |
Bytes |
"miner's public key" | User readable parameter description (string bytes in UTF-8 encoding) |
ConstantIndex |
VLQ(UInt) |
1 | Index in the ErgoTree.constants array |
Note, the ConstantIndex
field maps the parameters to the constants in the ExpressionTree
expression tree.
More specifically, given a contract template t: ContractTemplate
and a parameter p: Parameter
inside t
then p.ConstantIndex
is an index in t.ConstTypes
and
t.ConstValues
, such that c = t.ConstValues(p.ConstantIndex)
is a value of the constant
in t.ExpressionTree
which has the index p.ConstantIndex
.
This also means that there is a placeholder in t.ExpressionTree
which also refers to c
as if it were in constants
array of ErgoTree (i.e. we have p.ConstantIndex == ph.index
for some ph in t.ExpressionTree
).
Note, that each value in t.ConstValues
is optional, which means that for some parameters
the default value is not defined, however the type can always be looked up as
t = t.ConstTypes(p.ConstantIndex)
.
In addition to the binary format, the contract templates can be represented using JSON. It may serve better for some applications. Below we define the standard JSON representation of contract templates.
{
"name": "rewardOutputScript",
"description": "holds mining rewards",
"constTypes": ["0x04", "0x08"],
"constValues": ["0xa00b", "0xcd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"],
"parameters": [
{
"name": "minerPk",
"description": "miner's public key",
"constantIndex": 1
}
],
"templateTree": "ea02d192a39a8cc7a70173007301"
}
Notes:
- The
constTypes
property is required and the length of the array should be equal toConstNum
. Each element ofconstTypes
is Base16 encoded bytes of the corresponding serialized type (see Type format in ErgoTree spec). - If
ConstValues
is None, then it can be omitted in JSON or equal to null. In non null, then the length ofconstValues
array should be equal to the length ofconstTypes
. Missing constants should be represented as null values in the array. Every non-null value in the array should be Base16 encoded string of constant value serialized as Data format (see ErgoTree spec).
Contract template t
can be used to compose ErgoTree bytes as shown in the following
table, where t.name
means taking the corresponding field from the template t
.
Field Name | Format | Data Value |
---|---|---|
Header |
UByte |
t.TreeVersion plus additional bits |
ConstLength |
VLQ(UInt) |
t.ConstNum |
Constants |
Const+ |
Constants(i) = Constant(t.ConstTypes(i), t.ConstValues(i)) |
Template |
Expr |
t.ExpressionTree |
The template parameters (see t.Parameters
) can be used to substitute new values in the
Constants
thus redefining the default values of the template, or providing missing
constant values.
Note, ErgoTree composition from a template doesn't require an implementation of all the
ErgoTree serializers. Only Type Serializer and DataSerializer (see ErgoTree Specification)
have to be implemented to parse and serialize ConstTypes
and ConstValues
bytes,
replace the necessary constants (using ConstantIndex
field of the parameter) and then
serialize the updated array of the constants back to the new bytes array.
This relaxed requirement, will significantly simplify composition of valid ErgoTrees from templates on the platforms, where full serializer is not available. In particular, a template can be composed in one environment with full ErgoTree support and then transfered to another environment and used there for actual ErgoTree composition.
Compilers producing ErgoTree (such as ErgoScript, ErgoScala or others) can support this EIP directly buy generating a template packaged as either JSON or bytes.
For example, in the case of ErgoScala, the compiler is Scala macros. The programmer can specify the contract template metadata as annotations (on both contract method and its parameters) and the macros can access them and use for embedding into the template bytes.
The ErgoScala compiler macros maps the parameters of the Scala method to the segregated constants, however those constants are mixed with other constants in the contract body (which are not mapped to template parameters).
By using annotations the ErgoScala macros can map parameters to constant positions (in ErgoTree.constants array) and use this mapping both in compilation of ErgoTree and generation of the template bytes. In particular, when creating ErgoTree bytes, the ErgoScala macros can do partial constant segregation, i.e. segregate only those constants from the expression tree which are mapped to the parameters leaving others in the tree. Thus created contract template will also satisfy an additional requirement, i.e. the number of constants will be the same as the number of parameters.
Similar algorithm can be used in the other ErgoTree compiler implementations.