diff --git a/Makefile b/Makefile index a247f96a78..45687bc4f8 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ export GO111MODULE=on .PHONY: vendor vetcheck fmtcheck clean build gotest -all: vendor vetcheck build gotest mod-clean +all: vendor vetcheck fmtcheck build gotest mod-clean ver: @echo Building version: $(VERSION) diff --git a/cmd/node/node.go b/cmd/node/node.go index 2572dcb8f4..d183d6385b 100644 --- a/cmd/node/node.go +++ b/cmd/node/node.go @@ -87,7 +87,7 @@ var ( var defaultPeers = map[string]string{ "mainnet": "34.253.153.4:6868,168.119.116.189:6868,135.181.87.72:6868,35.158.218.156:6868,52.48.34.89:6868", - "testnet": "159.69.126.149:6863,94.130.105.239:6863,159.69.126.153:6863,94.130.172.201:6863", + "testnet": "159.69.126.149:6868,94.130.105.239:6868,159.69.126.153:6868,94.130.172.201:6868", "stagenet": "88.99.185.128:6862,49.12.15.166:6862,95.216.205.3:6862,88.198.179.16:6862", } diff --git a/go.sum b/go.sum index dfcce0cb5e..4747796f9c 100644 --- a/go.sum +++ b/go.sum @@ -83,7 +83,6 @@ github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/frozen/immutable_map v0.1.0 h1:JvDI2+lE4+5UJ8QJwxesBl4RuAEOmCJCZDXiAQXXIcY= github.com/frozen/immutable_map v0.1.0/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= diff --git a/pkg/ride/code_samples.go b/pkg/ride/code_samples.go deleted file mode 100644 index e49a59229c..0000000000 --- a/pkg/ride/code_samples.go +++ /dev/null @@ -1,35 +0,0 @@ -package ride - -const fcall1 = ` -func getInt(key: String) = { - match getInteger(this, key) { - case x : Int => x - case _ => 0 - } -} - -let a = getInt("5") -let b = getInt("6") -a == b -` - -const finf = ` -func abc() = { - func in() = { - true - } - in() -} -abc() -` - -const intersectNames = ` -{-# STDLIB_VERSION 3 #-} -{-# SCRIPT_TYPE ACCOUNT #-} -{-# CONTENT_TYPE EXPRESSION #-} -func inc(v: Int) = v + 1 -func call(inc: Int) = { - inc(inc) -} -call(2) == 3 -` diff --git a/pkg/ride/compiler.go b/pkg/ride/compiler.go index 97daf4b71d..17009bed36 100644 --- a/pkg/ride/compiler.go +++ b/pkg/ride/compiler.go @@ -17,6 +17,12 @@ func encode(v uint16) []byte { return b } +func encode32(v uint32) []byte { + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, v) + return b +} + func compile(f State, node Node) (State, error) { switch n := node.(type) { case *AssignmentNode: @@ -97,11 +103,11 @@ func CompileDapp(txID string, tree *Tree) (out *Executable, err error) { defer func() { if r := recover(); r != nil { zap.S().Error(DecompileTree(tree), " ", r) - err = errors.New("failed to compile") + err = errors.Errorf("failed to compile: %s", r.(string)) } }() if !tree.IsDApp() { - return nil, errors.Errorf("unable to compile dappp") + return nil, errors.Errorf("unable to compile DApp") } fns := tree.Functions if tree.HasVerifier() { diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 132e6da606..508eeeb538 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -8,7 +8,7 @@ type AssigmentState struct { bodyParams params prev State name string - n uniqueid + n uniqueID body Deferred d Deferreds } @@ -53,7 +53,7 @@ func (a AssigmentState) Boolean(v bool) State { return a } -func assigmentTransition(prev State, params params, name string, n uniqueid, d Deferreds) State { +func assigmentTransition(prev State, params params, name string, n uniqueID, d Deferreds) State { return newAssigment(prev, params, name, n, d) } @@ -62,7 +62,7 @@ func extendParams(p params) params { return p } -func newAssigment(prev State, p params, name string, n uniqueid, d Deferreds) State { +func newAssigment(prev State, p params, name string, n uniqueID, d Deferreds) State { return AssigmentState{ prev: prev, params: p, diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 1b66691c8d..5665461434 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -11,7 +11,7 @@ type CallSystemState struct { deferred []Deferred deferreds Deferreds // Sequential function arguments. - ns []uniqueid + ns []uniqueID } func (a CallSystemState) backward(state State) State { @@ -62,7 +62,7 @@ func callTransition(prev State, params params, name string, argc uint16, d Defer } func newCallSystemState(prev State, params params, name string, argc uint16, d Deferreds) State { - var ns []uniqueid + var ns []uniqueID for i := uint16(0); i < argc; i++ { ns = append(ns, params.u.next()) } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index a95647c113..72fa245919 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -9,7 +9,7 @@ type CallUserState struct { name string argc uint16 deferreds Deferreds - ns []uniqueid + ns []uniqueID } func (a CallUserState) backward(state State) State { diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 7d44d02b17..d70c1beebd 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -20,13 +20,13 @@ type ConditionalState struct { params prev State - rets []uint16 + rets []uint32 // Clean assigments after exit. deferred []Deferred deferreds Deferreds - condN uniqueid + condN uniqueID } func (a ConditionalState) backward(as State) State { @@ -126,19 +126,19 @@ func (a ConditionalState) Write(_ params, _ []byte) { a.b.write(encode(a.condN)) a.b.jpmIfFalse() - patchTruePosition := a.b.writeStub(2) - patchFalsePosition := a.b.writeStub(2) - patchNextPosition := a.b.writeStub(2) + patchTruePosition := a.b.writeStub(4) + patchFalsePosition := a.b.writeStub(4) + patchNextPosition := a.b.writeStub(4) - a.b.patch(patchTruePosition, encode(a.b.len())) + a.b.patch(patchTruePosition, encode32(a.b.len())) trueB.Write(a.params, nil) a.b.ret() - a.b.patch(patchFalsePosition, encode(a.b.len())) + a.b.patch(patchFalsePosition, encode32(a.b.len())) falsB.Write(a.params, nil) a.b.ret() - a.b.patch(patchNextPosition, encode(a.b.len())) + a.b.patch(patchNextPosition, encode32(a.b.len())) } func (a ConditionalState) Clean() { } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 7c7814cea6..dbce8e3e06 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -1,16 +1,18 @@ package ride -import "fmt" +import ( + "fmt" +) type arguments []string type Deferreds interface { - Add(Deferred, uniqueid, string) + Add(Deferred, uniqueID, string) } type dd struct { deferred Deferred - uniq uniqueid + uniq uniqueID debug string } @@ -19,7 +21,7 @@ type deferreds struct { d []dd } -func (a *deferreds) Add(deferred2 Deferred, n uniqueid, debug string) { +func (a *deferreds) Add(deferred2 Deferred, n uniqueID, debug string) { a.d = append(a.d, dd{ deferred: deferred2, uniq: n, @@ -36,9 +38,9 @@ type FuncState struct { prev State name string args arguments - n uniqueid + n uniqueID invokeParam string - paramIds []uniqueid + paramIds []uniqueID // References that defined inside function. deferred []Deferred @@ -72,7 +74,7 @@ func funcTransition(prev State, params params, name string, args []string, invok if invokeParam != "" { args = append([]string{invokeParam}, args...) } - paramIds := make([]uniqueid, 0, len(args)) + paramIds := make([]uniqueID, 0, len(args)) for i := range args { e := params.u.next() paramIds = append(paramIds, e) @@ -99,7 +101,7 @@ func (a FuncState) Assigment(name string) State { return assigmentTransition(a, a.params, name, n, a.defers) } -func (a FuncState) ParamIds() []uniqueid { +func (a FuncState) ParamIds() []uniqueID { return a.paramIds } @@ -152,13 +154,11 @@ func (a FuncState) Func(name string, args []string, invoke string) State { return funcTransition(a, a.params, name, args, invoke) } -func (a FuncState) Clean() { - -} +func (a FuncState) Clean() {} func (a FuncState) Write(_ params, _ []byte) { pos := a.b.len() - a.params.c.set(a.n, nil, 0, pos, false, fmt.Sprintf("function %s", a.name)) + a.params.c.set(a.n, nil, 0, pos, fmt.Sprintf("function %s", a.name)) if len(a.deferred) != 1 { panic("len(a.deferred) != 1") } @@ -170,17 +170,16 @@ func (a FuncState) Write(_ params, _ []byte) { } a.deferred[0].Write(a.params, nil) - // End of function body. Clear and write assigments. + // End of function body. Clear and write assignments. for _, v := range a.defers.Get() { v.deferred.Clean() } a.b.ret() for _, v := range a.defers.Get() { - pos := a.b.len() - a.c.set(v.uniq, nil, 0, pos, false, v.debug) + p := a.b.len() + a.c.set(v.uniq, nil, 0, p, v.debug) v.deferred.Write(a.params, nil) a.b.ret() } - } diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 3c2820612d..7a9ba24b3b 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -2,13 +2,13 @@ package ride import "bytes" -type constid = uint16 +type constID = uint16 type Refs map[uint16]point type Entrypoint struct { name string - at uint16 + at uint32 argn uint16 } @@ -17,7 +17,7 @@ func (a Entrypoint) Serialize(s Serializer) error { if err != nil { return err } - s.Uint16(a.at) + s.Uint32(a.at) s.Uint16(a.argn) return nil } @@ -29,7 +29,7 @@ func deserializeEntrypoint(d *Deserializer) (Entrypoint, error) { if err != nil { return a, err } - a.at, err = d.Uint16() + a.at, err = d.Uint32() if err != nil { return a, err } @@ -52,8 +52,8 @@ func newBuilder() *builder { } } -func (b *builder) writeStub(len int) (position uint16) { - position = uint16(b.w.Len()) +func (b *builder) writeStub(len int) (position uint32) { + position = uint32(b.w.Len()) for i := 0; i < len; i++ { b.w.WriteByte(0) } @@ -84,13 +84,13 @@ func (b *builder) ret() { b.w.WriteByte(OpReturn) } -func (b *builder) patch(at uint16, val []byte) { +func (b *builder) patch(at uint32, val []byte) { bts := b.w.Bytes()[at:] copy(bts, val) } -func (b *builder) len() uint16 { - return uint16(b.w.Len()) +func (b *builder) len() uint32 { + return uint32(b.w.Len()) } func (b *builder) externalCall(id uint16, argc uint16) { @@ -116,14 +116,14 @@ func (b *builder) write(i []byte) { } type point struct { - position uint16 + position uint32 value rideType fn uint16 debugInfo string } func (a point) Serialize(s Serializer) error { - s.Uint16(a.position) + s.Uint32(a.position) if a.value != nil { err := a.value.Serialize(s) if err != nil { @@ -148,7 +148,7 @@ func (a point) constant() bool { func deserializePoint(d *Deserializer) (point, error) { var a point var err error - a.position, err = d.Uint16() + a.position, err = d.Uint32() if err != nil { return a, err } @@ -168,16 +168,16 @@ func deserializePoint(d *Deserializer) (point, error) { } type cell struct { - values map[uniqueid]point + values map[uniqueID]point } func newCell() *cell { return &cell{ - values: make(map[uniqueid]point), + values: make(map[uniqueID]point), } } -func (a *cell) set(u uniqueid, result rideType, fn uint16, position uint16, constant bool, debug string) { +func (a *cell) set(u uniqueID, result rideType, fn uint16, position uint32, debug string) { a.values[u] = point{ position: position, value: result, @@ -186,11 +186,11 @@ func (a *cell) set(u uniqueid, result rideType, fn uint16, position uint16, cons } } -type uniqueid = uint16 +type uniqueID = uint16 type refKind struct { assigment bool - n uniqueid + n uniqueID } type references struct { @@ -205,23 +205,23 @@ func newReferences(prev *references) *references { } } -func (a *references) setAssigment(name string, uniq uniqueid) { - a.refs[name] = append([]refKind{refKind{assigment: true, n: uniq}}, a.refs[name]...) +func (a *references) setAssigment(name string, uniq uniqueID) { + a.refs[name] = append([]refKind{{assigment: true, n: uniq}}, a.refs[name]...) } -func (a *references) setFunc(name string, uniq uniqueid) { - a.refs[name] = append([]refKind{refKind{assigment: false, n: uniq}}, a.refs[name]...) +func (a *references) setFunc(name string, uniq uniqueID) { + a.refs[name] = append([]refKind{{assigment: false, n: uniq}}, a.refs[name]...) } -func (a *references) getFunc(name string) (uniqueid, bool) { +func (a *references) getFunc(name string) (uniqueID, bool) { return a.get(name, false) } -func (a *references) getAssigment(name string) (uniqueid, bool) { +func (a *references) getAssigment(name string) (uniqueID, bool) { return a.get(name, true) } -func (a *references) get(name string, assigment bool) (uniqueid, bool) { +func (a *references) get(name string, assigment bool) (uniqueID, bool) { if a == nil { return 0, false } @@ -285,7 +285,7 @@ type Deferred interface { } type constantDeferred struct { - n uniqueid + n uniqueID } func (a constantDeferred) Write(p params, _ []byte) { @@ -296,11 +296,11 @@ func (a constantDeferred) Write(p params, _ []byte) { func (a constantDeferred) Clean() { } -func NewConstantDeferred(n uniqueid) constantDeferred { +func newConstantDeferred(n uniqueID) constantDeferred { return constantDeferred{n: n} } -func isConstant(deferred Deferred) (uniqueid, bool) { +func isConstant(deferred Deferred) (uniqueID, bool) { v, ok := deferred.(constantDeferred) return v.n, ok } diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index cd93d4deee..9ce2be8fc9 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -89,7 +89,7 @@ func (a MainState) Return() State { for _, v := range a.deferreds.Get() { pos := a.b.len() - a.c.set(v.uniq, nil, 0, pos, false, v.debug) + a.c.set(v.uniq, nil, 0, pos, v.debug) v.deferred.Write(a.params, nil) a.b.ret() } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 1a0e4fc9c0..cb5d1ff166 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -8,7 +8,7 @@ type PropertyState struct { params body Deferred deferreds Deferreds - n uniqueid + n uniqueID } func (a PropertyState) backward(as State) State { @@ -25,8 +25,10 @@ func propertyTransition(prev State, params params, name string, d Deferreds) Sta } } -func (a PropertyState) Assigment(string) State { - panic("Illegal call `Assigment` on PropertyState") +func (a PropertyState) Assigment(name string) State { + n := a.params.u.next() + return assigmentTransition(a, a.params, name, n, a.deferreds) + //panic(fmt.Sprintf("Illegal call `Assigment` on PropertyState (n=%d; prop=%s; assignment=%s)", a.n, a.name, s)) } func (a PropertyState) Return() State { @@ -65,7 +67,8 @@ func (a PropertyState) String(string) State { } func (a PropertyState) Condition() State { - panic("Illegal call `Condition` on PropertyState") + return conditionalTransition(a, a.params, a.deferreds) + //panic("Illegal call `Condition` on PropertyState") } func (a PropertyState) TrueBranch() State { @@ -96,7 +99,7 @@ func (a PropertyState) Write(_ params, b []byte) { a.b.writeByte(OpRef) a.b.write(encode(a.n)) next := a.u.next() - a.c.set(next, rideString(a.name), 0, 0, true, fmt.Sprintf("property?? %s", a.name)) + a.c.set(next, rideString(a.name), 0, 0, fmt.Sprintf("property?? %s", a.name)) a.b.writeByte(OpRef) a.b.write(encode(next)) a.b.writeByte(OpProperty) diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 0f601db026..d29730a5c1 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -57,27 +57,27 @@ type params struct { txID string } -func (a *params) addPredefined(name string, id uniqueid, fn uint16) { +func (a *params) addPredefined(name string, id uniqueID, fn uint16) { a.r.setAssigment(name, id) - a.c.set(id, nil, fn, 0, false, name) + a.c.set(id, nil, fn, 0, name) } func (a *params) constant(value rideType) constantDeferred { switch v := value.(type) { case rideInt: if v >= 0 && v <= 100 { - return NewConstantDeferred(uniqueid(v)) + return newConstantDeferred(uniqueID(v)) } case rideBoolean: if v { - return NewConstantDeferred(101) + return newConstantDeferred(101) } else { - return NewConstantDeferred(102) + return newConstantDeferred(102) } } n := a.u.next() - a.c.set(n, value, 0, 0, true, fmt.Sprintf("constant %q", value)) - return NewConstantDeferred(n) + a.c.set(n, value, 0, 0, fmt.Sprintf("constant %q", value)) + return newConstantDeferred(n) } func reference(_ State, params params, name string) constantDeferred { @@ -85,5 +85,5 @@ func reference(_ State, params params, name string) constantDeferred { if !ok { panic(fmt.Sprintf("reference `%s` not found, tx %s", name, params.txID)) } - return NewConstantDeferred(pos) + return newConstantDeferred(pos) } diff --git a/pkg/ride/compiler_test.go b/pkg/ride/compiler_test.go index 738df55ace..919f7119d3 100644 --- a/pkg/ride/compiler_test.go +++ b/pkg/ride/compiler_test.go @@ -30,6 +30,7 @@ var defaultState = &MockSmartState{ }, nil }, } + var defaultEnv = &MockRideEnvironment{ transactionFunc: testTransferObject, stateFunc: func() types.SmartState { @@ -86,9 +87,9 @@ func TestCompiler(t *testing.T) { {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - {fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, - {finf, "BAoBAAAAA2FiYwAAAAAKAQAAAAJpbgAAAAAGCQEAAAACaW4AAAAACQEAAAADYWJjAAAAADpBKyM=", env, true}, - {intersectNames, "AwoBAAAAA2luYwAAAAEAAAABdgkAAGQAAAACBQAAAAF2AAAAAAAAAAABCgEAAAAEY2FsbAAAAAEAAAADaW5jCQEAAAADaW5jAAAAAQUAAAADaW5jCQAAAAAAAAIJAQAAAARjYWxsAAAAAQAAAAAAAAAAAgAAAAAAAAAAAxgTXMY=", env, true}, + {`func getInt(key: String) = {match getInteger(this, key) {case x: Int => x; case _ => 0;}}; let a = getInt("5"); let b = getInt("6"); a == b`, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, + {`func abc() = {func in() = true; in()}; abc()`, "BAoBAAAAA2FiYwAAAAAKAQAAAAJpbgAAAAAGCQEAAAACaW4AAAAACQEAAAADYWJjAAAAADpBKyM=", env, true}, + {`func inc(v: Int) = v + 1; func call(inc: Int) = inc(inc); call(2) == 3`, "AwoBAAAAA2luYwAAAAEAAAABdgkAAGQAAAACBQAAAAF2AAAAAAAAAAABCgEAAAAEY2FsbAAAAAEAAAADaW5jCQEAAAADaW5jAAAAAQUAAAADaW5jCQAAAAAAAAIJAQAAAARjYWxsAAAAAQAAAAAAAAAAAgAAAAAAAAAAAxgTXMY=", env, true}, {`func abc(addr: Address) = addr == tx.sender;abc(tx.sender)`, "BAoBAAAAA2FiYwAAAAEAAAAEYWRkcgkAAAAAAAACBQAAAARhZGRyCAUAAAACdHgAAAAGc2VuZGVyCQEAAAADYWJjAAAAAQgFAAAAAnR4AAAABnNlbmRlckJrXFI=", env, true}, {`let y = [{let x = 1;x}];true`, "BAQAAAABeQkABEwAAAACBAAAAAF4AAAAAAAAAAABBQAAAAF4BQAAAANuaWwGua/TXw==", env, true}, {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, @@ -102,6 +103,9 @@ func TestCompiler(t *testing.T) { {`HalfUp() == HALFUP`, `AwkAAAAAAAACCQEAAAAGSGFsZlVwAAAAAAUAAAAGSEFMRlVQbUfpTQ==`, nil, true}, {`let a0 = NoAlg() == NOALG; let a1 = Md5() == MD5; let a2 = Sha1() == SHA1; let a3 = Sha224() == SHA224; let a4 = Sha256() == SHA256; let a5 = Sha384() == SHA384; let a6 = Sha512() == SHA512; let a7 = Sha3224() == SHA3224; let a8 = Sha3256() == SHA3256; let a9 = Sha3384() == SHA3384; let a10 = Sha3512() == SHA3512; a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10`, `AwQAAAACYTAJAAAAAAAAAgkBAAAABU5vQWxnAAAAAAUAAAAFTk9BTEcEAAAAAmExCQAAAAAAAAIJAQAAAANNZDUAAAAABQAAAANNRDUEAAAAAmEyCQAAAAAAAAIJAQAAAARTaGExAAAAAAUAAAAEU0hBMQQAAAACYTMJAAAAAAAAAgkBAAAABlNoYTIyNAAAAAAFAAAABlNIQTIyNAQAAAACYTQJAAAAAAAAAgkBAAAABlNoYTI1NgAAAAAFAAAABlNIQTI1NgQAAAACYTUJAAAAAAAAAgkBAAAABlNoYTM4NAAAAAAFAAAABlNIQTM4NAQAAAACYTYJAAAAAAAAAgkBAAAABlNoYTUxMgAAAAAFAAAABlNIQTUxMgQAAAACYTcJAAAAAAAAAgkBAAAAB1NoYTMyMjQAAAAABQAAAAdTSEEzMjI0BAAAAAJhOAkAAAAAAAACCQEAAAAHU2hhMzI1NgAAAAAFAAAAB1NIQTMyNTYEAAAAAmE5CQAAAAAAAAIJAQAAAAdTaGEzMzg0AAAAAAUAAAAHU0hBMzM4NAQAAAADYTEwCQAAAAAAAAIJAQAAAAdTaGEzNTEyAAAAAAUAAAAHU0hBMzUxMgMDAwMDAwMDAwMFAAAAAmEwBQAAAAJhMQcFAAAAAmEyBwUAAAACYTMHBQAAAAJhNAcFAAAAAmE1BwUAAAACYTYHBQAAAAJhNwcFAAAAAmE4BwUAAAACYTkHBQAAAANhMTAHRc/wAA==`, env, true}, {`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, env, true}, + {`V4: let a = 1; let b = 2; let c = 3; let d = 4; let (x, y) = ((a+b), (c+d)); x + y == 10`, `BAQAAAABYQAAAAAAAAAAAQQAAAABYgAAAAAAAAAAAgQAAAABYwAAAAAAAAAAAwQAAAABZAAAAAAAAAAABAQAAAAJJHQwMTI2MTUzCQAFFAAAAAIJAABkAAAAAgUAAAABYQUAAAABYgkAAGQAAAACBQAAAAFjBQAAAAFkBAAAAAF4CAUAAAAJJHQwMTI2MTUzAAAAAl8xBAAAAAF5CAUAAAAJJHQwMTI2MTUzAAAAAl8yCQAAAAAAAAIJAABkAAAAAgUAAAABeAUAAAABeQAAAAAAAAAACrqIL8U=`, env, true}, + {`V4: func A() = (123, "xxx"); A()._1 == 123`, `BAoBAAAAAUEAAAAACQAFFAAAAAIAAAAAAAAAAHsCAAAAA3h4eAkAAAAAAAACCAkBAAAAAUEAAAAAAAAAAl8xAAAAAAAAAAB7Ge9bZg==`, env, true}, + {`V4: func A() = (123, "xxx"); func B() = A()._1; B() == 123`, `BAoBAAAAAUEAAAAACQAFFAAAAAIAAAAAAAAAAHsCAAAAA3h4eAoBAAAAAUIAAAAACAkBAAAAAUEAAAAAAAAAAl8xCQAAAAAAAAIJAQAAAAFCAAAAAAAAAAAAAAAAe7iMtSQ=`, env, true}, } { src, err := base64.StdEncoding.DecodeString(test.source) require.NoError(t, err, test.comment) @@ -111,11 +115,9 @@ func TestCompiler(t *testing.T) { assert.NotNil(t, tree, test.comment) tree = MustExpand(tree) - - script, err := CompileTree("", tree) - require.True(t, tree.Expanded) + script, err := CompileTree("", tree) require.NoError(t, err, test.comment) assert.NotNil(t, script, test.comment) @@ -128,8 +130,8 @@ func TestCompiler(t *testing.T) { } } -// 1 == 1 func TestCallExternal(t *testing.T) { + // 1 == 1 n := &FunctionCallNode{ Name: "0", Arguments: []Node{ @@ -158,8 +160,8 @@ func TestCallExternal(t *testing.T) { f.ByteCode) } -// let x = if (true) then true else false; x func TestIfConditionRightByteCode(t *testing.T) { + // let x = if (true) then true else false; x n := &AssignmentNode{ Name: "x", Expression: &ConditionalNode{ @@ -175,32 +177,13 @@ func TestIfConditionRightByteCode(t *testing.T) { f, err := compileFunction("", 3, []Node{n}, false, true) require.NoError(t, err) - /** - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 1, - OpClearCache, 0, 1, - OpReturn, - OpRef, 0, 2, - OpJumpIfFalse, 0, 0x12, 0, 0x16, 0, 0x1a, - OpRef, 0, 3, - OpReturn, - OpRef, 0, 4, - OpReturn, - OpReturn, - }, - f.ByteCode) - - /**/ - rs, err := f.Verify(nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } -// let i = 1; let s = "string"; toString(i) == s func TestCall(t *testing.T) { + // let i = 1; let s = "string"; toString(i) == s source := `BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -219,8 +202,8 @@ func TestCall(t *testing.T) { require.Equal(t, false, rs.Result()) } -//func a() = 1; a() == 1 func TestDoubleCall(t *testing.T) { + //func a() = 1; a() == 1 n := &FunctionDeclarationNode{ Name: "a", Arguments: nil, @@ -249,8 +232,8 @@ func TestDoubleCall(t *testing.T) { require.Equal(t, true, rs.Result()) } -// func id(v: Boolean) = v; id(true) func TestCallWithConstArg(t *testing.T) { + // func id(v: Boolean) = v; id(true) n := &FunctionDeclarationNode{ Name: "id", Arguments: []string{"v"}, @@ -274,8 +257,8 @@ func TestCallWithConstArg(t *testing.T) { require.Equal(t, true, rs.Result()) } -// func id(v: Boolean) = v && v; id(true) func TestMultipleCallConstantFuncArgument(t *testing.T) { + // func id(v: Boolean) = v && v; id(true) source := `BAoBAAAAAmlkAAAAAQAAAAF2AwUAAAABdgUAAAABdgcJAQAAAAJpZAAAAAEG3g2xRQ==` state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { @@ -313,25 +296,22 @@ func TestMultipleCallConstantFuncArgument(t *testing.T) { assert.Equal(t, true, r.Result()) } -/* -{-# STDLIB_VERSION 4 #-} -{-# CONTENT_TYPE EXPRESSION #-} -{-# SCRIPT_TYPE ACCOUNT #-} - -func id(v: Boolean) = { - if (v) then { - let x = throw("a") - 1 - } else { - let x = throw("b") - 2 - } -} - -1 == id(true) - -*/ func TestIfStmt(t *testing.T) { + /* + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + func id(v: Boolean) = { + if (v) then { + let x = throw("a") + 1 + } else { + let x = throw("b") + 2 + } + } + 1 == id(true) + */ source := `BAoBAAAAAmlkAAAAAQAAAAF2AwUAAAABdgQAAAABeAkAAAIAAAABAgAAAAFhAAAAAAAAAAABBAAAAAF4CQAAAgAAAAECAAAAAWIAAAAAAAAAAAIJAAAAAAAAAgAAAAAAAAAAAQkBAAAAAmlkAAAAAQYYAiEb` state := &MockSmartState{ NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { @@ -367,34 +347,23 @@ func TestIfStmt(t *testing.T) { require.NotNil(t, res) r, ok := res.(ScriptResult) require.True(t, ok) - - for _, l := range r.calls { - t.Log(l) - } - assert.Equal(t, true, r.Result()) } -/* -{-# STDLIB_VERSION 3 #-} -{-# CONTENT_TYPE DAPP #-} -{-# SCRIPT_TYPE ACCOUNT #-} - -@Callable(i) -func abc(question: String) = { - WriteSet([ - DataEntry("a", 5) - ]) -} - -@Callable(i) -func cba(question: String) = { - WriteSet([ - DataEntry("a", 6) - ]) -} -*/ func TestDappMultipleFunctions(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# CONTENT_TYPE DAPP #-} + {-# SCRIPT_TYPE ACCOUNT #-} + @Callable(i) + func abc(question: String) = { + WriteSet([DataEntry("a", 5)]) + } + @Callable(i) + func cba(question: String) = { + WriteSet([DataEntry("a", 6)]) + } + */ source := "AAIDAAAAAAAAAAwIARIDCgEIEgMKAQgAAAAAAAAAAgAAAAFpAQAAAANhYmMAAAABAAAACHF1ZXN0aW9uCQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFhAAAAAAAAAAAFBQAAAANuaWwAAAABaQEAAAADY2JhAAAAAQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQAAAAAAAAAABgUAAAADbmlsAAAAAFEpRso=" src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -430,41 +399,15 @@ func TestDappMultipleFunctions(t *testing.T) { }, []proto.ScriptAction(rs.ScriptActions())) } -/* - -func finalizeCurrentPrice() { - let prices = 1100( - getOracleProvideHeight( - 401(oraclesList,0), - height - ), - 1100(getOracleProvideHeight(401(oraclesList,1),height), - 1100(getOracleProvideHeight(401(oraclesList,2,),height,), - 1100(getOracleProvideHeight(401(oraclesList,3,),height,), - 1100(getOracleProvideHeight(401(oraclesList,4,),height,),nil,),),),),); - let priceProvidingCount = ((((if (!=(401(prices,0,),0,)) { 1 } else { 0 } + if (!=(401(prices,1,),0,)) { 1 } else { 0 }) + if (!=(401(prices,2,),0,)) { 1 } else { 0 }) + if (!=(401(prices,3,),0,)) { 1 } else { 0 }) + if (!=(401(prices,4,),0,)) { 1 } else { 0 }); - let priceSum = ((((401(prices,0,) + 401(prices,1,)) + 401(prices,2,)) + 401(prices,3,)) + 401(prices,4,)); - let newPrice = 105(priceSum,priceProvidingCount,); - if (isBlocked) { - 2("contract is blocked") - } else { - if (102(bftCoefficientOracle,priceProvidingCount)) { - 2( - 300( - 300( - 420(bftCoefficientOracle), - "/5 oracles need to set a price " - ), - 420(priceProvidingCount) - ) - ) - } else { - if (if (103(newPrice,(price + 105(104(price,percentPriceOffset,),100,)),)) { true } else { 103((price - 105(104(price,percentPriceOffset,),100,)),newPrice,) }) { WriteSet(1100(DataEntry(IsBlockedKey,true,),1100(DataEntry(getBlackSwarmPriceKey(height,),newPrice,),nil,),),) } else { let newPriceIndex = (priceIndex + 1); WriteSet(1100(DataEntry(PriceKey,newPrice,),1100(DataEntry(getPriceHistoryKey(height,),newPrice,),1100(DataEntry(PriceIndexKey,newPriceIndex,),1100(DataEntry(getHeightPriceByIndexKey(newPriceIndex,),height,),nil,),),),),) } } } } - - -*/ - -func Test777(t *testing.T) { +func TestList(t *testing.T) { + /* + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE EXPRESSION #-} + let oraclesList = ["3MSNMcqyweiM9cWpvf4Fn8GAWeuPstxj2hK"] + func getNumberByAddressAndKey(address: Address, key: Int) = 0 + func getOracleProvideHeight(owner: String, height: Int) = getNumberByAddressAndKey(addressFromStringValue(owner), height) + getOracleProvideHeight(oraclesList[0], height) == 1 + */ source := `BAQAAAALb3JhY2xlc0xpc3QJAARMAAAAAgIAAAAjM01TTk1jcXl3ZWlNOWNXcHZmNEZuOEdBV2V1UHN0eGoyaEsFAAAAA25pbAoBAAAAGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQAAAAIAAAAHYWRkcmVzcwAAAANrZXkAAAAAAAAAAAAKAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgAAAAVvd25lcgAAAAZoZWlnaHQJAQAAABhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABBQAAAAVvd25lcgUAAAAGaGVpZ2h0CQAAAAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAAUAAAAGaGVpZ2h0AAAAAAAAAAABHUHhjA==` state := &MockSmartState{ @@ -517,16 +460,16 @@ func Test777(t *testing.T) { assert.Equal(t, false, r.Result()) } -/* -func abc() = 5 -func cba() = 10 -if abc() == cba() then { - true -} else { - false -} -*/ -func Test888(t *testing.T) { +func TestFunctionCallInline(t *testing.T) { + /* + func abc() = 5 + func cba() = 10 + if abc() == cba() then { + true + } else { + false + } + */ source := `BAoBAAAAA2FiYwAAAAAAAAAAAAAAAAUKAQAAAANjYmEAAAAAAAAAAAAAAAAKAwkAAAAAAAACCQEAAAADYWJjAAAAAAkBAAAAA2NiYQAAAAAGB0hjUOM=` state := &MockSmartState{ @@ -570,71 +513,42 @@ func Test888(t *testing.T) { script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) - - /** - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 0, - OpRef, 0, 0, - OpCall, 0, 0, 0, 2, - OpJumpIfFalse, 0, 0, 0, 0, 0, 0, - OpRef, 0, 0, OpReturn, //true branch - OpRef, 0, 0, OpReturn, //false branch - OpReturn, - OpRef, 0, 0, OpReturn, // function cba - OpRef, 0, 0, OpReturn, // function abc - }, - script.ByteCode) - /**/ - rs, _ := script.Verify(env) require.Equal(t, rs.Result(), false) - //require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"") } -/* - -{-# STDLIB_VERSION 3 #-} -{-# SCRIPT_TYPE ACCOUNT #-} -{-# CONTENT_TYPE DAPP #-} - -func getStringByAddressAndKey(address: Address, key: String) = match getString(address, key) { - case a: String => - a - case _ => - "" -} - -func getStringByKey(key: String) = match getString(this, key) { - case a: String => - a - case _ => - "" -} - -let LastConfirmTxKey = "last_confirm_tx" -let NeutrinoContractKey = "neutrino_contract" -let ControlContractKey = "control_contract" -let neutrinoContract = addressFromStringValue(getStringByKey(NeutrinoContractKey)) -let controlContract = addressFromStringValue(getStringByAddressAndKey(neutrinoContract, ControlContractKey)) -let lastConfirmTx = getStringByAddressAndKey(controlContract, LastConfirmTxKey) - -@Verifier(tx) -func verify () = (lastConfirmTx == toBase58String(tx.id)) - -*/ func TestNoDuplicateCallToState(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# CONTENT_TYPE DAPP #-} + func getStringByAddressAndKey(address: Address, key: String) = match getString(address, key) { + case a: String => + a + case _ => + "" + } + func getStringByKey(key: String) = match getString(this, key) { + case a: String => + a + case _ => + "" + } + let LastConfirmTxKey = "last_confirm_tx" + let NeutrinoContractKey = "neutrino_contract" + let ControlContractKey = "control_contract" + let neutrinoContract = addressFromStringValue(getStringByKey(NeutrinoContractKey)) + let controlContract = addressFromStringValue(getStringByAddressAndKey(neutrinoContract, ControlContractKey)) + let lastConfirmTx = getStringByAddressAndKey(controlContract, LastConfirmTxKey) + @Verifier(tx) + func verify () = (lastConfirmTx == toBase58String(tx.id)) + */ source := `AAIDAAAAAAAAAAIIAQAAAAgBAAAAGGdldFN0cmluZ0J5QWRkcmVzc0FuZEtleQAAAAIAAAAHYWRkcmVzcwAAAANrZXkEAAAAByRtYXRjaDAJAAQdAAAAAgUAAAAHYWRkcmVzcwUAAAADa2V5AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAAZTdHJpbmcEAAAAAWEFAAAAByRtYXRjaDAFAAAAAWECAAAAAAEAAAAOZ2V0U3RyaW5nQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABB0AAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABlN0cmluZwQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQIAAAAAAAAAABBMYXN0Q29uZmlybVR4S2V5AgAAAA9sYXN0X2NvbmZpcm1fdHgAAAAAE05ldXRyaW5vQ29udHJhY3RLZXkCAAAAEW5ldXRyaW5vX2NvbnRyYWN0AAAAABJDb250cm9sQ29udHJhY3RLZXkCAAAAEGNvbnRyb2xfY29udHJhY3QAAAAAEG5ldXRyaW5vQ29udHJhY3QJAQAAABxAZXh0clVzZXIoYWRkcmVzc0Zyb21TdHJpbmcpAAAAAQkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQUAAAATTmV1dHJpbm9Db250cmFjdEtleQAAAAAPY29udHJvbENvbnRyYWN0CQEAAAAcQGV4dHJVc2VyKGFkZHJlc3NGcm9tU3RyaW5nKQAAAAEJAQAAABhnZXRTdHJpbmdCeUFkZHJlc3NBbmRLZXkAAAACBQAAABBuZXV0cmlub0NvbnRyYWN0BQAAABJDb250cm9sQ29udHJhY3RLZXkAAAAADWxhc3RDb25maXJtVHgJAQAAABhnZXRTdHJpbmdCeUFkZHJlc3NBbmRLZXkAAAACBQAAAA9jb250cm9sQ29udHJhY3QFAAAAEExhc3RDb25maXJtVHhLZXkAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAAAAAAACBQAAAA1sYXN0Q29uZmlybVR4CQACWAAAAAEIBQAAAAJ0eAAAAAJpZJO+lgc=` state := &MockSmartState{ NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { return byte_helpers.TransferWithProofs.Transaction, nil }, - //RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { - // t.Log("key: ", key) - // return nil, errors.New("not found") - //}, RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { switch key { case "neutrino_contract": @@ -687,22 +601,18 @@ func TestNoDuplicateCallToState(t *testing.T) { rs, err := script.Verify(env) require.NoError(t, err) - for _, c := range rs.Calls() { - t.Log(c) - } require.NoError(t, err) require.False(t, rs.Result()) } -/* -{-# STDLIB_VERSION 3 #-} -{-# SCRIPT_TYPE ACCOUNT #-} -{-# CONTENT_TYPE DAPP #-} - -@Verifier(tx) -func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) -*/ func TestDappVerifyVm(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# CONTENT_TYPE DAPP #-} + @Verifier(tx) + func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) + */ source := `AAIDAAAAAAAAAAIIAQAAAAAAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAfQAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAAIBQAAAAJ0eAAAAA9zZW5kZXJQdWJsaWNLZXlQ99ml` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -730,18 +640,17 @@ func TestDappVerifyVm(t *testing.T) { require.Equal(t, rs.Result(), true) } -/* -{-# STDLIB_VERSION 3 #-} -{-# SCRIPT_TYPE ACCOUNT #-} -{-# CONTENT_TYPE EXPRESSION #-} - -match (tx) { - case e:ExchangeTransaction => isDefined(e.sellOrder.assetPair.priceAsset) - case _ => throw("err") - } -*/ func TestMultipleProperty(t *testing.T) { - source := `AwQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE0V4Y2hhbmdlVHJhbnNhY3Rpb24EAAAAAWUFAAAAByRtYXRjaDAJAQAAAAlpc0RlZmluZWQAAAABCAgIBQAAAAFlAAAACXNlbGxPcmRlcgAAAAlhc3NldFBhaXIAAAAKcHJpY2VBc3NldAkAAAIAAAABAgAAAANlcnIsqB0K` + /* + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# CONTENT_TYPE EXPRESSION #-} + + match (tx) { + case e:ExchangeTransaction => isDefined(e.sellOrder.assetPair.priceAsset) + case _ => throw("err") + } + */source := `AwQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE0V4Y2hhbmdlVHJhbnNhY3Rpb24EAAAAAWUFAAAAByRtYXRjaDAJAQAAAAlpc0RlZmluZWQAAAABCAgIBQAAAAFlAAAACXNlbGxPcmRlcgAAAAlhc3NldFBhaXIAAAAKcHJpY2VBc3NldAkAAAIAAAABAgAAAANlcnIsqB0K` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -841,15 +750,15 @@ func TestProperty(t *testing.T) { }) } -/* -{-# STDLIB_VERSION 4 #-} -{-# CONTENT_TYPE EXPRESSION #-} -{-# SCRIPT_TYPE ACCOUNT #-} - -let x = 1 + 1 -x == x -*/ func TestCacheInMain(t *testing.T) { + /* + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + let x = 1 + 1 + x == x + */ source := `BAQAAAABeAkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABCQAAAAAAAAIFAAAAAXgFAAAAAXgu3TzS` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -866,36 +775,23 @@ func TestCacheInMain(t *testing.T) { transactionFunc: testExchangeWithProofsToObject, } - /** - require.Equal(t, []byte{ - OpReturn, - 0xe, 0x0, 0xc9, - OpReturn, - OpRef, 0x0, 0xc9, - OpCache, 0x0, 0xc9, - OpRef, 0x0, 0xc9, - OpCache, 0x0, 0xc9, - OpExternalCall, 0x0, 0x3, 0x0, 0x2, OpReturn, - }, script.ByteCode) - /**/ - rs, err := script.Verify(env) require.NoError(t, err) require.Equal(t, 2, len(rs.Calls())) // plus & eq require.Equal(t, rs.Result(), true) } -/* -{-# STDLIB_VERSION 4 #-} -{-# CONTENT_TYPE EXPRESSION #-} -{-# SCRIPT_TYPE ACCOUNT #-} -func abc() = { - 1 + 1 -} -let info = abc() -info == info -*/ func TestCacheFunctionArgumentsCalls(t *testing.T) { + /* + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + func abc() = { + 1 + 1 + } + let info = abc() + info == info + */ source := `BAoBAAAAA2FiYwAAAAAJAABkAAAAAgAAAAAAAAAAAQAAAAAAAAAAAQQAAAAEaW5mbwkBAAAAA2FiYwAAAAAJAAAAAAAAAgUAAAAEaW5mbwUAAAAEaW5mby35E+E=` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -918,18 +814,18 @@ func TestCacheFunctionArgumentsCalls(t *testing.T) { require.Equal(t, true, rs.Result()) } -/* -{-# STDLIB_VERSION 4 #-} -{-# CONTENT_TYPE EXPRESSION #-} -{-# SCRIPT_TYPE ACCOUNT #-} - -func abc() = { - let x = 1 + 1 - x == x -} -abc() -*/ func TestCacheInFunc(t *testing.T) { + /* + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + + func abc() = { + let x = 1 + 1 + x == x + } + abc() + */ source := `BAoBAAAAA2FiYwAAAAAEAAAAAXgJAABkAAAAAgAAAAAAAAAAAQAAAAAAAAAAAQkAAAAAAAACBQAAAAF4BQAAAAF4CQEAAAADYWJjAAAAAJz8J24=` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -952,15 +848,15 @@ func TestCacheInFunc(t *testing.T) { require.Equal(t, rs.Result(), true) } -/* -{-# STDLIB_VERSION 4 #-} -{-# CONTENT_TYPE EXPRESSION #-} -{-# SCRIPT_TYPE ACCOUNT #-} -func abc(x: Int) = x == x -let y = getIntegerValue(this, "a") -abc(y) -*/ func TestCacheFuncArgs(t *testing.T) { + /* + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + func abc(x: Int) = x == x + let y = getIntegerValue(this, "a") + abc(y) + */ source := `BAoBAAAAA2FiYwAAAAEAAAABeAkAAAAAAAACBQAAAAF4BQAAAAF4BAAAAAF5CQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAAR0aGlzAgAAAAFhCQEAAAADYWJjAAAAAQUAAAABeYsrE7g=` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -998,14 +894,14 @@ func TestCacheFuncArgs(t *testing.T) { require.Equal(t, "0", rs.Calls()[1].name) } -/* -let x = { - let y = true; - y; -} -x -*/ func TestLetInLet(t *testing.T) { + /* + let x = { + let y = true; + y; + } + x + */ source := `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -1015,7 +911,6 @@ func TestLetInLet(t *testing.T) { assert.NotNil(t, tree) script, err := CompileVerifier("", tree) - t.Log(Decompiler(tree.Verifier)) require.NoError(t, err) assert.NotNil(t, script) @@ -1023,73 +918,52 @@ func TestLetInLet(t *testing.T) { transactionFunc: testExchangeWithProofsToObject, } - /* * - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 1, - OpClearCache, 0, 2, - OpClearCache, 0, 1, - OpReturn, - OpRef, 0, 2, - //OpReturn, - }, - script.ByteCode[:11]) - /**/ - rs, err := script.Verify(env) require.NoError(t, err) require.Equal(t, true, rs.Result()) } -/* -{-# STDLIB_VERSION 3 #-} -{-# SCRIPT_TYPE ACCOUNT #-} -{-# CONTENT_TYPE DAPP #-} - - -@Callable(i) -func deposit () = { - let pmt = extract(i.payment) - if (isDefined(pmt.assetId)) - then throw("can hold waves only at the moment") - else { - let currentKey = toBase58String(i.caller.bytes) - let currentAmount = match getInteger(this, currentKey) { - case a: Int => - a - case _ => - 0 - } - let newAmount = (currentAmount + pmt.amount) - WriteSet([DataEntry(currentKey, newAmount)]) - } - } - - - -@Callable(i) -func withdraw (amount) = { - let currentKey = toBase58String(i.caller.bytes) - let currentAmount = match getInteger(this, currentKey) { - case a: Int => - a - case _ => - 0 - } - let newAmount = (currentAmount - amount) - if ((0 > amount)) - then throw("Can't withdraw negative amount") - else if ((0 > newAmount)) - then throw("Not enough balance") - else ScriptResult(WriteSet([DataEntry(currentKey, newAmount)]), TransferSet([ScriptTransfer(i.caller, amount, unit)])) - } - - -@Verifier(tx) -func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) -*/ -func TestDDaa(t *testing.T) { +func TestDApp(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# CONTENT_TYPE DAPP #-} + @Callable(i) + func deposit () = { + let pmt = extract(i.payment) + if (isDefined(pmt.assetId)) + then throw("can hold waves only at the moment") + else { + let currentKey = toBase58String(i.caller.bytes) + let currentAmount = match getInteger(this, currentKey) { + case a: Int => + a + case _ => + 0 + } + let newAmount = (currentAmount + pmt.amount) + WriteSet([DataEntry(currentKey, newAmount)]) + } + } + @Callable(i) + func withdraw (amount) = { + let currentKey = toBase58String(i.caller.bytes) + let currentAmount = match getInteger(this, currentKey) { + case a: Int => + a + case _ => + 0 + } + let newAmount = (currentAmount - amount) + if ((0 > amount)) + then throw("Can't withdraw negative amount") + else if ((0 > newAmount)) + then throw("Not enough balance") + else ScriptResult(WriteSet([DataEntry(currentKey, newAmount)]), TransferSet([ScriptTransfer(i.caller, amount, unit)])) + } + @Verifier(tx) + func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) + */ source := `AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -1153,6 +1027,7 @@ func BenchmarkVm(b *testing.B) { for i := 0; i < b.N; i++ { b.StartTimer() rs, err := script.Verify(env) + require.NoError(b, err) require.Equal(b, 5, len(rs.Calls())) b.StopTimer() require.NoError(b, err) @@ -1269,6 +1144,7 @@ func BenchmarkVmWithDeserialize(b *testing.B) { exe, err := DeserializeExecutable(bts) require.NoError(b, err) rs, err := exe.Verify(env) + require.NoError(b, err) require.Equal(b, 5, len(rs.Calls())) b.StopTimer() require.NoError(b, err) @@ -1326,25 +1202,23 @@ func BenchmarkTreeWithDeserialize(b *testing.B) { } } -/* -{-# STDLIB_VERSION 4 #-} -{-# CONTENT_TYPE EXPRESSION #-} -{-# SCRIPT_TYPE ACCOUNT #-} - -if (true) then { - func a() = { - true - } - a() -} else { - func b() = { - false - } - b() -} -*/ - func TestFuncInCondState(t *testing.T) { + /* + {-# STDLIB_VERSION 4 #-} + {-# CONTENT_TYPE EXPRESSION #-} + {-# SCRIPT_TYPE ACCOUNT #-} + if (true) then { + func a() = { + true + } + a() + } else { + func b() = { + false + } + b() + } + */ source := `BAMGCgEAAAABYQAAAAAGCQEAAAABYQAAAAAKAQAAAAFiAAAAAAcJAQAAAAFiAAAAAObLaEQ=` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -1400,11 +1274,14 @@ func TestFuncInCondState(t *testing.T) { require.True(t, rs1.Eq(rs2)) } -/* - - */ - -func Test111111(t *testing.T) { +func TestFuncNameAndParameterCollision(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# CONTENT_TYPE EXPRESSION #-} + func inc(v: Int) = v + 1 + func call(inc: Int) = inc(inc) + call(2) == 3 + */ source := `AwoBAAAAA2luYwAAAAEAAAABdgkAAGQAAAACBQAAAAF2AAAAAAAAAAABCgEAAAAEY2FsbAAAAAEAAAADaW5jCQEAAAADaW5jAAAAAQUAAAADaW5jCQAAAAAAAAIJAQAAAARjYWxsAAAAAQAAAAAAAAAAAgAAAAAAAAAAAxgTXMY=` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -1452,25 +1329,22 @@ func Test111111(t *testing.T) { require.NoError(t, err) rs, err := exe.Verify(env) require.NoError(t, err) - for i, c := range rs.Calls() { - t.Log(i, " ", c) - } + assert.True(t, rs.Result()) } -/** -let height = height -height != 0 -*/ func TestShadowedVariable(t *testing.T) { + /* + let height = height + height != 0 + */ source := `AwoBAAAAD2dldFByaWNlSGlzdG9yeQAAAAEAAAAGaGVpZ2h0BQAAAAZoZWlnaHQJAQAAAAIhPQAAAAIJAQAAAA9nZXRQcmljZUhpc3RvcnkAAAABBQAAAAZoZWlnaHQAAAAAAAAAAADe0Skk` - src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) tree, err := Parse(src) require.NoError(t, err) tree = MustExpand(tree) - require.Equal(t, "(let height$getPriceHistory = { height }; height$getPriceHistory != 0)", DecompileTree(tree)) + require.Equal(t, "(let height@getPriceHistory = { height }; height@getPriceHistory != 0)", DecompileTree(tree)) script, err := CompileTree("", tree) require.NoError(t, err) @@ -1480,24 +1354,23 @@ func TestShadowedVariable(t *testing.T) { require.Equal(t, true, rs.Result()) } -/** -{-# STDLIB_VERSION 3 #-} -{-# SCRIPT_TYPE ACCOUNT #-} -{-# CONTENT_TYPE EXPRESSION #-} - -let prevOrder = false -func internal(prevOrder: Boolean) = { - if (prevOrder) - then false - else true -} -if (false) - then false - else internal(prevOrder) -*/ func TestShadowedVariableInConditionStmt(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# CONTENT_TYPE EXPRESSION #-} + + let prevOrder = false + func internal(prevOrder: Boolean) = { + if (prevOrder) + then false + else true + } + if (false) + then false + else internal(prevOrder) + */ source := `AwQAAAAJcHJldk9yZGVyBwoBAAAACGludGVybmFsAAAAAQAAAAlwcmV2T3JkZXIDBQAAAAlwcmV2T3JkZXIHBgMHBwkBAAAACGludGVybmFsAAAAAQUAAAAJcHJldk9yZGVyxqI+QQ==` - src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -1512,3 +1385,36 @@ func TestShadowedVariableInConditionStmt(t *testing.T) { require.NoError(t, err) require.Equal(t, true, rs.Result()) } + +func TestFailedCompilationOnPropertyAssignment(t *testing.T) { + source := "AAIEAAAAAAAAABYIAhIAEgASBQoDCAgIEgASBQoDCAEBAAAARwEAAAARa2V5QWNjdW11bGF0ZWRGZWUAAAAAAgAAABIlc19fYWNjdW11bGF0ZWRGZWUBAAAADmtleVVjb2xsYXRlcmFsAAAAAAIAAAAPJXNfX3Vjb2xsYXRlcmFsAQAAABlrZXlUb3RhbExlbmRlZEF0T3RoZXJBY2NzAAAAAAIAAAAaJXNfX3RvdGFsTGVuZGVkQXRPdGhlckFjY3MBAAAAE2tleUFzc2V0TG9ja2VkVG90YWwAAAABAAAAB2Fzc2V0SWQJAAEsAAAAAgIAAAAYJXMlc19fYXNzZXRMb2NrZWRUb3RhbF9fBQAAAAdhc3NldElkAQAAABNrZXlBY2NvdW50T3BlcmF0aW9uAAAAAwAAAAx1bmxvY2tIZWlnaHQAAAAHYWRkcmVzcwAAAAZzdGF0dXMJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAAB4lcyVzJWQlc19fZGVmb0Fzc2V0T3BlcmF0aW9uX18FAAAAB2FkZHJlc3MCAAAAAl9fCQABpAAAAAEFAAAADHVubG9ja0hlaWdodAIAAAACX18FAAAABnN0YXR1cwEAAAAKa2V5RmFjdG9yeQAAAAACAAAACyVzX19mYWN0b3J5AQAAABprZXlMZW5kZWRBbW91bnRCeUFzc2V0Q29kZQAAAAEAAAAJYXNzZXRDb2RlCQABLAAAAAICAAAAHSVzJXNfX2xlbmRlZEJhc2VBc3NldEFtb3VudF9fBQAAAAlhc3NldENvZGUBAAAACGtleVByaWNlAAAAAQAAAAlhc3NldENvZGUJAAEsAAAAAgIAAAANJXMlc19fcHJpY2VfXwUAAAAJYXNzZXRDb2RlAAAAABRJZHhPcGVyYXRpb25BbW91bnRJbgAAAAAAAAAAAQAAAAATSWR4T3BlcmF0aW9uQXNzZXRJbgAAAAAAAAAAAgAAAAARSWR4T3BlcmF0aW9uUHJpY2UAAAAAAAAAAAMAAAAAFUlkeE9wZXJhdGlvbkFtb3VudE91dAAAAAAAAAAABAAAAAAUSWR4T3BlcmF0aW9uQXNzZXRPdXQAAAAAAAAAAAUBAAAAFmFzc2V0RGF0YVN3YXBPcGVyYXRpb24AAAAHAAAACGFtb3VudEluAAAAB2Fzc2V0SW4AAAAFcHJpY2UAAAAJYW1vdW50T3V0AAAACGFzc2V0T3V0AAAADGJydXR0b0Ftb3VudAAAAAlmZWVBbW91bnQJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAAQJWQlcyVkJXMlZCVkJWRfXwkAAaQAAAABBQAAAAhhbW91bnRJbgIAAAACX18FAAAAB2Fzc2V0SW4CAAAAAl9fCQABpAAAAAEFAAAACWFtb3VudE91dAIAAAACX18FAAAACGFzc2V0T3V0AgAAAAJfXwkAAaQAAAABBQAAAAVwcmljZQIAAAACX18JAAGkAAAAAQUAAAAMYnJ1dHRvQW1vdW50AgAAAAJfXwkAAaQAAAABBQAAAAlmZWVBbW91bnQBAAAAF2Fzc2V0RGF0YVJlYmFsYW5jZVRyYWNlAAAABQAAAA9kZWJ0b3JBc3NldENvZGUAAAAHZGVidFBtdAAAAAdiYXNlUG10AAAAD2xlbmRlZEFtdEJlZm9yZQAAAA5sZW5kZWRBbXRBZnRlcgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAABAlcyVzJWQlcyVkJWQlZF9fBQAAAA9kZWJ0b3JBc3NldENvZGUCAAAAAl9fCQACWAAAAAEJAQAAAAV2YWx1ZQAAAAEIBQAAAAdkZWJ0UG10AAAAB2Fzc2V0SWQCAAAAAl9fCQABpAAAAAEIBQAAAAdkZWJ0UG10AAAABmFtb3VudAIAAAACX18JAAJYAAAAAQkBAAAABXZhbHVlAAAAAQgFAAAAB2Jhc2VQbXQAAAAHYXNzZXRJZAIAAAACX18JAAGkAAAAAQgFAAAAB2Jhc2VQbXQAAAAGYW1vdW50AgAAAAJfXwkAAaQAAAABBQAAAA9sZW5kZWRBbXRCZWZvcmUCAAAAAl9fCQABpAAAAAEFAAAADmxlbmRlZEFtdEFmdGVyAQAAABxhc3NldFJlYWRTd2FwRGF0YUFycmF5T3JGYWlsAAAAAQAAAA9hY2NPcGVyYXRpb25LZXkEAAAAE2FjY09wZXJhdGlvbkRhdGFTdHIJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAAR0aGlzBQAAAA9hY2NPcGVyYXRpb25LZXkJAAEsAAAAAgIAAAAqVGhlcmUgaXMgbm8gcmVxdWVzdCBmb3IgcGFzc2VkIGFyZ3VtZW50czogBQAAAA9hY2NPcGVyYXRpb25LZXkJAAS1AAAAAgUAAAATYWNjT3BlcmF0aW9uRGF0YVN0cgIAAAACX18AAAAAB251bGxJbnQA//////////8AAAAAB251bGxTdHICAAAABE5VTEwAAAAACmZhY3RvcnlBY2MJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAAR0aGlzCQEAAAAKa2V5RmFjdG9yeQAAAAAJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAEk5vIGNvbmZpZyBhdCB0aGlzPQkABCUAAAABBQAAAAR0aGlzAgAAAAkgZm9yIGtleT0JAQAAAAprZXlGYWN0b3J5AAAAAAEAAAAVa2V5RmFjdG9yeURlYnRBc3NldElkAAAAAAIAAAAfJXMlc19fY29tbW9uQ29uZmlnX19kZWJ0QXNzZXRJZAEAAAASa2V5RmFjdG9yeUFzc2V0Q2ZnAAAAAQAAAA9hc3NldEFkZHJlc3NTdHIJAAEsAAAAAgkAASwAAAACAgAAABMlcyVzJXNfX2RlZm9Bc3NldF9fBQAAAA9hc3NldEFkZHJlc3NTdHICAAAACF9fY29uZmlnAQAAABprZXlGYWN0b3J5QXNzZXRDdXJyZW50UG9vbAAAAAEAAAAPYXNzZXRBY2NBZGRyZXNzCQABLAAAAAIJAAEsAAAAAgIAAAATJXMlcyVzX19kZWZvQXNzZXRfXwkABCUAAAABBQAAAA9hc3NldEFjY0FkZHJlc3MCAAAADV9fY3VycmVudFBvb2wBAAAAIGtleUZhY3RvcnlEZWZvQWRkcmVzc0J5QXNzZXRDb2RlAAAAAQAAAAlhc3NldENvZGUJAAEsAAAAAgkAASwAAAACAgAAABMlcyVzJXNfX2RlZm9Bc3NldF9fBQAAAAlhc3NldENvZGUCAAAAFF9fYWRkcmVzc0J5QXNzZXRDb2RlAQAAABZmYWN0b3J5UmVhZERlYnRBc3NldElkAAAAAAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAACmZhY3RvcnlBY2MJAQAAABVrZXlGYWN0b3J5RGVidEFzc2V0SWQAAAAACQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAABVObyBjb25maWcgYXQgZmFjdG9yeT0JAAQlAAAAAQUAAAAKZmFjdG9yeUFjYwIAAAAJIGZvciBrZXk9CQEAAAAVa2V5RmFjdG9yeURlYnRBc3NldElkAAAAAAEAAAAcZmFjdG9yeVJlYWRBc3NldENmZ0J5QWRkcmVzcwAAAAEAAAAPYXNzZXRBZGRyZXNzU3RyCQAEtQAAAAIJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAApmYWN0b3J5QWNjCQEAAAASa2V5RmFjdG9yeUFzc2V0Q2ZnAAAAAQUAAAAPYXNzZXRBZGRyZXNzU3RyCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAABVObyBjb25maWcgYXQgZmFjdG9yeT0JAAQlAAAAAQUAAAAKZmFjdG9yeUFjYwIAAAAJIGZvciBrZXk9CQEAAAASa2V5RmFjdG9yeUFzc2V0Q2ZnAAAAAQUAAAAPYXNzZXRBZGRyZXNzU3RyAgAAAAJfXwEAAAAZZmFjdG9yeVJlYWRBc3NldENmZ0J5Q29kZQAAAAEAAAAJYXNzZXRDb2RlBAAAAA9hc3NldEFkZHJlc3NTdHIJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAApmYWN0b3J5QWNjCQEAAAAga2V5RmFjdG9yeURlZm9BZGRyZXNzQnlBc3NldENvZGUAAAABBQAAAAlhc3NldENvZGUJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAFU5vIGNvbmZpZyBhdCBmYWN0b3J5PQkABCUAAAABBQAAAApmYWN0b3J5QWNjAgAAAAkgZm9yIGtleT0JAQAAACBrZXlGYWN0b3J5RGVmb0FkZHJlc3NCeUFzc2V0Q29kZQAAAAEFAAAACWFzc2V0Q29kZQkABRQAAAACBQAAAA9hc3NldEFkZHJlc3NTdHIJAQAAABxmYWN0b3J5UmVhZEFzc2V0Q2ZnQnlBZGRyZXNzAAAAAQUAAAAPYXNzZXRBZGRyZXNzU3RyAAAAABBJZHhEZWZvQXNzZXRDb2RlAAAAAAAAAAABAAAAAA5JZHhEZWZvQXNzZXRJZAAAAAAAAAAAAgAAAAASSWR4RGVmb0Fzc2V0U3RhdHVzAAAAAAAAAAADAAAAABBJZHhQcmljZURlY2ltYWxzAAAAAAAAAAAEAAAAAA5JZHhCYXNlQXNzZXRJZAAAAAAAAAAABQAAAAAYSWR4T3ZlckNvbGxhdGVyYWxQZXJjZW50AAAAAAAAAAAGAAAAAA5JZHhNaW5Jbml0UG9vbAAAAAAAAAAABwAAAAAVSWR4UHJpY2VPcmFjbGVBZGRyZXNzAAAAAAAAAAAIAAAAABBJZHhNaW5CdXlQYXltZW50AAAAAAAAAAAJAAAAABFJZHhNaW5TZWxsUGF5bWVudAAAAAAAAAAACgAAAAASSWR4QnV5TG9ja0ludGVydmFsAAAAAAAAAAALAAAAABNJZHhTZWxsTG9ja0ludGVydmFsAAAAAAAAAAAMAAAAABBJZHhCdXlGZWVQZXJjZW50AAAAAAAAAAANAAAAABFJZHhTZWxsRmVlUGVyY2VudAAAAAAAAAAADgAAAAAMdGhpc0NmZ0FycmF5CQEAAAAcZmFjdG9yeVJlYWRBc3NldENmZ0J5QWRkcmVzcwAAAAEJAAQlAAAAAQUAAAAEdGhpcwAAAAANZGVmb0Fzc2V0Q29kZQkAAZEAAAACBQAAAAx0aGlzQ2ZnQXJyYXkFAAAAEElkeERlZm9Bc3NldENvZGUAAAAAC2RlZm9Bc3NldElkCQACWQAAAAEJAAGRAAAAAgUAAAAMdGhpc0NmZ0FycmF5BQAAAA5JZHhEZWZvQXNzZXRJZAAAAAAOcHJpY2VPcmFjbGVBY2MJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEJAAGRAAAAAgUAAAAMdGhpc0NmZ0FycmF5BQAAABVJZHhQcmljZU9yYWNsZUFkZHJlc3MAAAAAFW92ZXJDb2xsYXRlcmFsUGVyY2VudAkBAAAADXBhcnNlSW50VmFsdWUAAAABCQABkQAAAAIFAAAADHRoaXNDZmdBcnJheQUAAAAYSWR4T3ZlckNvbGxhdGVyYWxQZXJjZW50AAAAAA5iYXNlQXNzZXRJZFN0cgkAAZEAAAACBQAAAAx0aGlzQ2ZnQXJyYXkFAAAADklkeEJhc2VBc3NldElkAAAAAAtiYXNlQXNzZXRJZAkAAlkAAAABBQAAAA5iYXNlQXNzZXRJZFN0cgAAAAANcHJpY2VEZWNpbWFscwkBAAAADXBhcnNlSW50VmFsdWUAAAABCQABkQAAAAIFAAAADHRoaXNDZmdBcnJheQUAAAAQSWR4UHJpY2VEZWNpbWFscwAAAAARbWluQmFzaWNCdXlBbW91bnQJAQAAAA1wYXJzZUludFZhbHVlAAAAAQkAAZEAAAACBQAAAAx0aGlzQ2ZnQXJyYXkFAAAAEElkeE1pbkJ1eVBheW1lbnQAAAAAEm1pblN5bnRoU2VsbEFtb3VudAkBAAAADXBhcnNlSW50VmFsdWUAAAABCQABkQAAAAIFAAAADHRoaXNDZmdBcnJheQUAAAARSWR4TWluU2VsbFBheW1lbnQAAAAAD2J1eUxvY2tJbnRlcnZhbAkBAAAADXBhcnNlSW50VmFsdWUAAAABCQABkQAAAAIFAAAADHRoaXNDZmdBcnJheQUAAAASSWR4QnV5TG9ja0ludGVydmFsAAAAABBzZWxsTG9ja0ludGVydmFsCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEJAAGRAAAAAgUAAAAMdGhpc0NmZ0FycmF5BQAAABNJZHhTZWxsTG9ja0ludGVydmFsAAAAAA1idXlGZWVQZXJjZW50CQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEJAAGRAAAAAgUAAAAMdGhpc0NmZ0FycmF5BQAAABBJZHhCdXlGZWVQZXJjZW50AAAAAA5zZWxsRmVlUGVyY2VudAkBAAAADXBhcnNlSW50VmFsdWUAAAABCQABkQAAAAIFAAAADHRoaXNDZmdBcnJheQUAAAARSWR4U2VsbEZlZVBlcmNlbnQBAAAAE2NvbnRyb2xBY2NSZWFkUHJpY2UAAAABAAAACWFzc2V0Q29kZQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAADnByaWNlT3JhY2xlQWNjCQEAAAAIa2V5UHJpY2UAAAABBQAAAAlhc3NldENvZGUJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAGE5vIHByaWNlIGF0IHByaWNlT3JhY2xlPQkABCUAAAABBQAAAA5wcmljZU9yYWNsZUFjYwIAAAAJIGZvciBrZXk9CQEAAAAIa2V5UHJpY2UAAAABBQAAAAlhc3NldENvZGUBAAAAG2NvbnRyb2xBY2NSZWFkQ3VycklkeE9yRmFpbAAAAAAJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAA5wcmljZU9yYWNsZUFjYwIAAAAHY3VycklkeAkAASwAAAACAgAAABlObyBjdXJySWR4IGF0IGNvbnRyb2xBY2M9CQAEJQAAAAEFAAAADnByaWNlT3JhY2xlQWNjAQAAABdjb250cm9sQWNjUmVhZElkeEhlaWdodAAAAAEAAAADaWR4BAAAAAxpZHhIZWlnaHRLZXkJAAEsAAAAAgIAAAAKaWR4SGVpZ2h0XwkAAaQAAAABBQAAAANpZHgJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAOcHJpY2VPcmFjbGVBY2MFAAAADGlkeEhlaWdodEtleQAAAAAAAAAAAAEAAAAbY29udHJvbEFjY1JlYWRQcmljZUJ5SGVpZ2h0AAAAAQAAAAtwcmljZUhlaWdodAQAAAAQcHJpY2VCeUhlaWdodEtleQkAASwAAAACAgAAAAZwcmljZV8JAAGkAAAAAQUAAAALcHJpY2VIZWlnaHQJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAA5wcmljZU9yYWNsZUFjYwUAAAAQcHJpY2VCeUhlaWdodEtleQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAADTm8gBQAAABBwcmljZUJ5SGVpZ2h0S2V5AgAAAA8gYXQgY29udHJvbEFjYz0JAAQlAAAAAQUAAAAOcHJpY2VPcmFjbGVBY2MBAAAAEWdldFN0YWtpbmdCYWxhbmNlAAAAAAkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAAAxycGRfYmFsYW5jZV8FAAAADmJhc2VBc3NldElkU3RyAgAAAAFfCQAEJQAAAAEFAAAABHRoaXMAAAAAAAAAAAAAAAAAC3Vjb2xsYXRlcmFsCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMJAQAAAA5rZXlVY29sbGF0ZXJhbAAAAAAAAAAAAAAAAAAAAAAADmFjY3VtdWxhdGVkRmVlCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMJAQAAABFrZXlBY2N1bXVsYXRlZEZlZQAAAAAAAAAAAAAAAAAAAAAADmN1cnJQb29sQW1vdW50CQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAApmYWN0b3J5QWNjCQEAAAAaa2V5RmFjdG9yeUFzc2V0Q3VycmVudFBvb2wAAAABBQAAAAR0aGlzAAAAABdkb3VibGVDaGVja0Jhc2ljQmFsYW5jZQkAAGQAAAACCQAD8AAAAAIFAAAABHRoaXMFAAAAC2Jhc2VBc3NldElkCQEAAAARZ2V0U3Rha2luZ0JhbGFuY2UAAAAAAAAAABZkb3VibGVDaGVja1Vjb2xsYXRlcmFsAwkAAGYAAAACAAAAAAAAAAAABQAAAAt1Y29sbGF0ZXJhbAAAAAAAAAAAAAUAAAALdWNvbGxhdGVyYWwAAAAAGWRvdWJsZUNoZWNrQ3VyclBvb2xBbW91bnQJAABlAAAAAgUAAAAXZG91YmxlQ2hlY2tCYXNpY0JhbGFuY2UFAAAAC3Vjb2xsYXRlcmFsAAAAAAVwcmljZQkBAAAAE2NvbnRyb2xBY2NSZWFkUHJpY2UAAAABCQABkQAAAAIFAAAADHRoaXNDZmdBcnJheQUAAAAQSWR4RGVmb0Fzc2V0Q29kZQAAAAAJb3ZlclByaWNlCQAAaQAAAAIJAABoAAAAAgkAAGQAAAACBQAAAA1wcmljZURlY2ltYWxzBQAAABVvdmVyQ29sbGF0ZXJhbFBlcmNlbnQFAAAABXByaWNlBQAAAA1wcmljZURlY2ltYWxzAAAAAAhlbWlzc2lvbggJAQAAAAV2YWx1ZQAAAAEJAAPsAAAAAQUAAAALZGVmb0Fzc2V0SWQAAAAIcXVhbnRpdHkAAAAAE2Jhc2ljQXNzZXRMb2NrZWRBbXQJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwkBAAAAE2tleUFzc2V0TG9ja2VkVG90YWwAAAABBQAAAA5iYXNlQXNzZXRJZFN0cgAAAAAAAAAAAAAAAAAUYXZhaWxhYmxlUG9vbEJhbGFuY2UJAABlAAAAAgUAAAAOY3VyclBvb2xBbW91bnQFAAAAE2Jhc2ljQXNzZXRMb2NrZWRBbXQBAAAAEGludGVybmFsQnV5QXNzZXQAAAAGAAAACnNlbGxlckFkZHIAAAAHc2VsbEFtdAAAAAtzZWxsQXNzZXRJZAAAAAptaW5TZWxsQW10AAAADWJ1eTJzZWxsUHJpY2UAAAAKZmVlUGVyY2VudAQAAAAYYXZhaWxhYmxlRGVmb0Fzc2V0SW5Qb29sCQAAZQAAAAIJAABrAAAAAwUAAAAUYXZhaWxhYmxlUG9vbEJhbGFuY2UFAAAADXByaWNlRGVjaW1hbHMFAAAACW92ZXJQcmljZQUAAAAIZW1pc3Npb24EAAAAHmZ1bGxEZWZvQXNzZXRBbW91bnROb1Bvb2xMaW1pdAkAAGsAAAADBQAAAAdzZWxsQW10BQAAAA1wcmljZURlY2ltYWxzBQAAAA1idXkyc2VsbFByaWNlBAAAABlmdWxsRGVmb0Fzc2V0QW1vdW50QnJ1dHRvAwkAAGYAAAACBQAAAB5mdWxsRGVmb0Fzc2V0QW1vdW50Tm9Qb29sTGltaXQFAAAAGGF2YWlsYWJsZURlZm9Bc3NldEluUG9vbAUAAAAYYXZhaWxhYmxlRGVmb0Fzc2V0SW5Qb29sBQAAAB5mdWxsRGVmb0Fzc2V0QW1vdW50Tm9Qb29sTGltaXQEAAAAD2RlZm9Bc3NldEFtb3VudAkAAGsAAAADCQAAZQAAAAIFAAAADXByaWNlRGVjaW1hbHMFAAAACmZlZVBlcmNlbnQFAAAAGWZ1bGxEZWZvQXNzZXRBbW91bnRCcnV0dG8FAAAADXByaWNlRGVjaW1hbHMEAAAACWZlZUFtb3VudAkAAGUAAAACBQAAABlmdWxsRGVmb0Fzc2V0QW1vdW50QnJ1dHRvBQAAAA9kZWZvQXNzZXRBbW91bnQEAAAAGHJlcXVpcmVkQmFzaWNBc3NldEFtb3VudAkAAGsAAAADBQAAABlmdWxsRGVmb0Fzc2V0QW1vdW50QnJ1dHRvBQAAAA1idXkyc2VsbFByaWNlBQAAAA1wcmljZURlY2ltYWxzBAAAAAZjaGFuZ2UJAABlAAAAAgUAAAAHc2VsbEFtdAUAAAAYcmVxdWlyZWRCYXNpY0Fzc2V0QW1vdW50AwkAAGcAAAACAAAAAAAAAAAABQAAABhhdmFpbGFibGVEZWZvQXNzZXRJblBvb2wJAAACAAAAAQkAASwAAAACCQABLAAAAAICAAAAGGltcG9zc2libGUgdG8gaXNzdWUgbmV3IAUAAAANZGVmb0Fzc2V0Q29kZQIAAAAXOiBub3QgZW5vdWdoIGNvbGxhdGVyYWwDCQAAZgAAAAIFAAAACm1pblNlbGxBbXQFAAAAB3NlbGxBbXQJAAACAAAAAQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAGGltcG9zc2libGUgdG8gaXNzdWUgbmV3IAUAAAANZGVmb0Fzc2V0Q29kZQIAAAAKOiBwYXltZW50PQkAAaQAAAABBQAAAAdzZWxsQW10AgAAABhpcyBsZXNzIHRoZW4gbWluIGFtb3VudD0JAAGkAAAAAQUAAAAKbWluU2VsbEFtdAkABRQAAAACCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAOa2V5VWNvbGxhdGVyYWwAAAAACQAAZAAAAAIFAAAAC3Vjb2xsYXRlcmFsBQAAABhyZXF1aXJlZEJhc2ljQXNzZXRBbW91bnQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAE2tleUFjY291bnRPcGVyYXRpb24AAAADBQAAAAZoZWlnaHQJAAQlAAAAAQUAAAAKc2VsbGVyQWRkcgIAAAAIRklOSVNIRUQJAQAAABZhc3NldERhdGFTd2FwT3BlcmF0aW9uAAAABwUAAAAHc2VsbEFtdAkAAlgAAAABBQAAAAtzZWxsQXNzZXRJZAUAAAAFcHJpY2UFAAAAD2RlZm9Bc3NldEFtb3VudAkAAlgAAAABBQAAAAtkZWZvQXNzZXRJZAUAAAAZZnVsbERlZm9Bc3NldEFtb3VudEJydXR0bwUAAAAJZmVlQW1vdW50CQAETAAAAAIJAQAAAAdSZWlzc3VlAAAAAwUAAAALZGVmb0Fzc2V0SWQJAABkAAAAAgUAAAAPZGVmb0Fzc2V0QW1vdW50BQAAAAlmZWVBbW91bnQGCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMFAAAACnNlbGxlckFkZHIFAAAAD2RlZm9Bc3NldEFtb3VudAUAAAALZGVmb0Fzc2V0SWQJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAKc2VsbGVyQWRkcgUAAAAGY2hhbmdlBQAAAAtzZWxsQXNzZXRJZAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEWtleUFjY3VtdWxhdGVkRmVlAAAAAAkAAGQAAAACBQAAAA5hY2N1bXVsYXRlZEZlZQUAAAAJZmVlQW1vdW50BQAAAANuaWwFAAAABmNoYW5nZQAAAAUAAAABaQEAAAAIYnV5QXNzZXQAAAAABAAAAANwbXQJAQAAAAV2YWx1ZQAAAAEJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAEAAAACnBtdEFzc2V0SWQJAQAAAAV2YWx1ZQAAAAEIBQAAAANwbXQAAAAHYXNzZXRJZAMJAQAAAAIhPQAAAAIFAAAACnBtdEFzc2V0SWQFAAAAC2Jhc2VBc3NldElkCQAAAgAAAAEJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAANVBheW1lbnQgYXNzZXQgaWQgZG9lc24ndCBtYXRjaCBiYXNpYyBhc3NldDogZXhwZWN0ZWQ9CQACWAAAAAEFAAAAC2Jhc2VBc3NldElkAgAAAAggYWN0dWFsPQkAAlgAAAABBQAAAApwbXRBc3NldElkCAkBAAAAEGludGVybmFsQnV5QXNzZXQAAAAGCAUAAAABaQAAAAZjYWxsZXIIBQAAAANwbXQAAAAGYW1vdW50BQAAAApwbXRBc3NldElkBQAAABFtaW5CYXNpY0J1eUFtb3VudAUAAAAFcHJpY2UFAAAADWJ1eUZlZVBlcmNlbnQAAAACXzEAAAABaQEAAAAJc2VsbEFzc2V0AAAAAAQAAAADcG10CQEAAAAFdmFsdWUAAAABCQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAABAAAAAhwbXRBc3NldAkBAAAABXZhbHVlAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkBAAAAA1jYWxsZXJBZGRyZXNzCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgMJAQAAAAIhPQAAAAIFAAAACHBtdEFzc2V0BQAAAAtkZWZvQXNzZXRJZAkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAACNJbnZhbGlkIHBheW1lbnQgYXNzZXQgaWQ6IGV4cGVjdGVkPQkAAlgAAAABBQAAAAtkZWZvQXNzZXRJZAIAAAAIIGFjdHVhbD0JAAJYAAAAAQUAAAAIcG10QXNzZXQDCQAAZgAAAAIFAAAAEm1pblN5bnRoU2VsbEFtb3VudAgFAAAAA3BtdAAAAAZhbW91bnQJAAACAAAAAQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAA6UGF5bWVudCBhbW91bnQgbGVzcyB0aGVuIG1pbmluaW1hbCBhbGxvd2VkOiBwYXltZW50QW1vdW50PQkAAaQAAAABCAUAAAADcG10AAAABmFtb3VudAIAAAALIG1pbkFtb3VudD0JAAGkAAAAAQUAAAASbWluU3ludGhTZWxsQW1vdW50BAAAABJwbXREZWZvQW1vdW50R3Jvc3MIBQAAAANwbXQAAAAGYW1vdW50BAAAAA1kZWZvQW1vdW50RmVlCQAAawAAAAMJAABlAAAAAgUAAAANcHJpY2VEZWNpbWFscwUAAAAOc2VsbEZlZVBlcmNlbnQFAAAAEnBtdERlZm9BbW91bnRHcm9zcwUAAAANcHJpY2VEZWNpbWFscwQAAAAScG10RGVmb0Ftb3VudE5vRmVlCQAAZQAAAAIFAAAAEnBtdERlZm9BbW91bnRHcm9zcwUAAAANZGVmb0Ftb3VudEZlZQQAAAAdYmFzZUFzc2V0QW1vdW50Tm9CYWxhbmNlTGltaXQJAABrAAAAAwUAAAAScG10RGVmb0Ftb3VudE5vRmVlBQAAAAVwcmljZQUAAAANcHJpY2VEZWNpbWFscwQAAAAUYmFzZUFzc2V0QW1vdW50Tm9GZWUDCQAAZgAAAAIFAAAAHWJhc2VBc3NldEFtb3VudE5vQmFsYW5jZUxpbWl0BQAAABlkb3VibGVDaGVja0N1cnJQb29sQW1vdW50BQAAABlkb3VibGVDaGVja0N1cnJQb29sQW1vdW50BQAAAB1iYXNlQXNzZXRBbW91bnROb0JhbGFuY2VMaW1pdAQAAAAXcmVxdWlyZWREZWZvQXNzZXRBbW91bnQJAABrAAAAAwUAAAAUYmFzZUFzc2V0QW1vdW50Tm9GZWUFAAAADXByaWNlRGVjaW1hbHMFAAAABXByaWNlBAAAAAZjaGFuZ2UJAABlAAAAAgUAAAAScG10RGVmb0Ftb3VudE5vRmVlBQAAABdyZXF1aXJlZERlZm9Bc3NldEFtb3VudAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAADmtleVVjb2xsYXRlcmFsAAAAAAkAAGUAAAACBQAAAAt1Y29sbGF0ZXJhbAUAAAAUYmFzZUFzc2V0QW1vdW50Tm9GZWUJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAE2tleUFjY291bnRPcGVyYXRpb24AAAADBQAAAAZoZWlnaHQFAAAADWNhbGxlckFkZHJlc3MCAAAACEZJTklTSEVECQEAAAAWYXNzZXREYXRhU3dhcE9wZXJhdGlvbgAAAAcIBQAAAANwbXQAAAAGYW1vdW50CQACWAAAAAEFAAAACHBtdEFzc2V0BQAAAAVwcmljZQUAAAAUYmFzZUFzc2V0QW1vdW50Tm9GZWUFAAAADmJhc2VBc3NldElkU3RyBQAAABJwbXREZWZvQW1vdW50R3Jvc3MFAAAADWRlZm9BbW91bnRGZWUJAARMAAAAAgkBAAAABEJ1cm4AAAACBQAAAAtkZWZvQXNzZXRJZAUAAAAXcmVxdWlyZWREZWZvQXNzZXRBbW91bnQJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAABRiYXNlQXNzZXRBbW91bnROb0ZlZQUAAAALYmFzZUFzc2V0SWQJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZjaGFuZ2UFAAAAC2RlZm9Bc3NldElkCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAARa2V5QWNjdW11bGF0ZWRGZWUAAAAACQAAZAAAAAIFAAAADmFjY3VtdWxhdGVkRmVlBQAAAA1kZWZvQW1vdW50RmVlBQAAAANuaWwAAAABaQEAAAANY3Jvc3NFeGNoYW5nZQAAAAMAAAAKYnV5QXNzZXRJZAAAABNidXlBc3NldENvZGVDb25maXJtAAAAFHNlbGxBc3NldENvZGVDb25maXJtBAAAAANwbXQJAQAAAAV2YWx1ZQAAAAEJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAEAAAACHBtdEFzc2V0CQEAAAAFdmFsdWUAAAABCAUAAAADcG10AAAAB2Fzc2V0SWQEAAAAC3BtdEFzc2V0U3RyCQACWAAAAAEFAAAACHBtdEFzc2V0BAAAAAlwbXRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50BAAAAA1jYWxsZXJBZGRyZXNzCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgQAAAALYnV5QXNzZXRDZmcFAAAADHRoaXNDZmdBcnJheQQAAAAOc2VsbEFzc2V0VHVwbGUJAQAAABlmYWN0b3J5UmVhZEFzc2V0Q2ZnQnlDb2RlAAAAAQUAAAAUc2VsbEFzc2V0Q29kZUNvbmZpcm0EAAAADHNlbGxBc3NldENmZwgFAAAADnNlbGxBc3NldFR1cGxlAAAAAl8yBAAAABNzZWxsQXNzZXRBY2NBZGRyZXNzCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQmAAAAAQgFAAAADnNlbGxBc3NldFR1cGxlAAAAAl8xCQABLAAAAAICAAAAMWNvdWxkbid0IHBhcnNlIGFkZHJlc3MgZnJvbSBzdHJpbmcgZm9yIGFzc2V0Q29kZT0FAAAAFHNlbGxBc3NldENvZGVDb25maXJtBAAAAAptaW5TZWxsUG10CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAS2AAAAAQkAAZEAAAACBQAAAAxzZWxsQXNzZXRDZmcFAAAAEUlkeE1pblNlbGxQYXltZW50CQABLAAAAAICAAAAIW1pblNlbGxQbXQgcGFyc2luZyBlcnJvcjogcmF3VmFsPQkAAZEAAAACBQAAAAxzZWxsQXNzZXRDZmcFAAAAEUlkeE1pblNlbGxQYXltZW50AwkBAAAAAiE9AAAAAgkAAZEAAAACBQAAAAx0aGlzQ2ZnQXJyYXkFAAAADklkeERlZm9Bc3NldElkBQAAAApidXlBc3NldElkCQAAAgAAAAEJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAMGJ1eUFzc2V0IGNvbmZpcm1hdGlvbiBmYWlsZWQ6IGJ1eUFzc2V0SWRDb25maXJtPQkAAZEAAAACBQAAAAx0aGlzQ2ZnQXJyYXkFAAAADklkeERlZm9Bc3NldElkAgAAABAgQlVUIGJ1eUFzc2V0SWQ9BQAAAApidXlBc3NldElkAwkBAAAAAiE9AAAAAgkAAZEAAAACBQAAAAxzZWxsQXNzZXRDZmcFAAAADklkeERlZm9Bc3NldElkBQAAAAtwbXRBc3NldFN0cgkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAADJzZWxsQXNzZXQgY29uZmlybWF0aW9uIGZhaWxlZDogc2VsbEFzc2V0SWRDb25maXJtPQkAAZEAAAACBQAAAAxzZWxsQXNzZXRDZmcFAAAADklkeERlZm9Bc3NldElkAgAAAA1CVVQgcG10QXNzZXQ9BQAAAAtwbXRBc3NldFN0cgMJAQAAAAIhPQAAAAIJAAGRAAAAAgUAAAAMdGhpc0NmZ0FycmF5BQAAABJJZHhEZWZvQXNzZXRTdGF0dXMCAAAABklTU1VFRAkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAACx0b0Fzc2V0IGhhcyBub3QgYmVlbiBpc3N1ZWQgeWV0OiBidXlBc3NldElkPQUAAAAKYnV5QXNzZXRJZAIAAAAMIEJVVCBzdGF0dXM9CQABkQAAAAIFAAAADHRoaXNDZmdBcnJheQUAAAASSWR4RGVmb0Fzc2V0U3RhdHVzAwkBAAAAAiE9AAAAAgkAAZEAAAACBQAAAAxzZWxsQXNzZXRDZmcFAAAAEklkeERlZm9Bc3NldFN0YXR1cwIAAAAGSVNTVUVECQAAAgAAAAEJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAMmZyb21Bc3NldENmZyBoYXMgbm90IGJlZW4gaXNzdWVkIHlldDogc2VsbEFzc2V0SWQ9BQAAAAtwbXRBc3NldFN0cgIAAAAMIEJVVCBzdGF0dXM9CQABkQAAAAIFAAAADHNlbGxBc3NldENmZwUAAAASSWR4RGVmb0Fzc2V0U3RhdHVzBAAAABBidXlBc3NldFVzZFByaWNlBQAAAAVwcmljZQQAAAARc2VsbEFzc2V0VXNkUHJpY2UJAQAAABNjb250cm9sQWNjUmVhZFByaWNlAAAAAQUAAAAUc2VsbEFzc2V0Q29kZUNvbmZpcm0EAAAADWJ1eTJzZWxsUHJpY2UJAABrAAAAAwUAAAAQYnV5QXNzZXRVc2RQcmljZQUAAAANcHJpY2VEZWNpbWFscwUAAAARc2VsbEFzc2V0VXNkUHJpY2UEAAAAC2RlYnRBc3NldElkCQACWQAAAAEJAQAAABZmYWN0b3J5UmVhZERlYnRBc3NldElkAAAAAAQAAAAIdXNkbkRlYnQJAABrAAAAAwUAAAARc2VsbEFzc2V0VXNkUHJpY2UFAAAACXBtdEFtb3VudAUAAAANcHJpY2VEZWNpbWFscwQAAAAWdG90YWxMZW5kZWRBdE90aGVyQWNjcwkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzCQEAAAAZa2V5VG90YWxMZW5kZWRBdE90aGVyQWNjcwAAAAAAAAAAAAAAAAAEAAAAGmxlbmRlZEFtb3VudEJ5QXNzZXRDb2RlS2V5CQEAAAAaa2V5TGVuZGVkQW1vdW50QnlBc3NldENvZGUAAAABBQAAABRzZWxsQXNzZXRDb2RlQ29uZmlybQQAAAAUbGVuZGVkQW10QnlBc3NldENvZGUJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAAabGVuZGVkQW1vdW50QnlBc3NldENvZGVLZXkAAAAAAAAAAAAEAAAADmJ1eUFzc2V0UmVzdWx0CQEAAAAQaW50ZXJuYWxCdXlBc3NldAAAAAYIBQAAAAFpAAAABmNhbGxlcgUAAAAJcG10QW1vdW50BQAAAAhwbXRBc3NldAUAAAAKbWluU2VsbFBtdAUAAAANYnV5MnNlbGxQcmljZQkAAGsAAAADBQAAAA1idXlGZWVQZXJjZW50AAAAAAAAAACWAAAAAAAAAABkCQAETQAAAAIJAARNAAAAAggFAAAADmJ1eUFzc2V0UmVzdWx0AAAAAl8xCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAabGVuZGVkQW1vdW50QnlBc3NldENvZGVLZXkJAABkAAAAAgUAAAAUbGVuZGVkQW10QnlBc3NldENvZGUFAAAACHVzZG5EZWJ0CQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAGWtleVRvdGFsTGVuZGVkQXRPdGhlckFjY3MAAAAACQAAZAAAAAIFAAAAFnRvdGFsTGVuZGVkQXRPdGhlckFjY3MFAAAACHVzZG5EZWJ0AAAAAWkBAAAADnJlYmFsYW5jZURlYnRzAAAAAAQAAAALZGVidEFzc2V0SWQJAAJZAAAAAQkBAAAAFmZhY3RvcnlSZWFkRGVidEFzc2V0SWQAAAAABAAAAAhkZWJ0UG10MAkBAAAABXZhbHVlAAAAAQkAAZEAAAACCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAQAAAANZGVidFBtdEFzc2V0MAkBAAAABXZhbHVlAAAAAQgFAAAACGRlYnRQbXQwAAAAB2Fzc2V0SWQEAAAACGJhc2VQbXQxCQEAAAAFdmFsdWUAAAABCQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAABBAAAAA1iYXNlUG10QXNzZXQxCQEAAAAFdmFsdWUAAAABCAUAAAAIYmFzZVBtdDEAAAAHYXNzZXRJZAQAAAANZGVidG9yQWRkcmVzcwkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIEAAAADmRlYnRvckFzc2V0Q2ZnCQEAAAAcZmFjdG9yeVJlYWRBc3NldENmZ0J5QWRkcmVzcwAAAAEFAAAADWRlYnRvckFkZHJlc3MEAAAAD2RlYnRvckFzc2V0Q29kZQkAAZEAAAACBQAAAA5kZWJ0b3JBc3NldENmZwUAAAAQSWR4RGVmb0Fzc2V0Q29kZQQAAAAabGVuZGVkQW1vdW50QnlBc3NldENvZGVLZXkJAQAAABprZXlMZW5kZWRBbW91bnRCeUFzc2V0Q29kZQAAAAEFAAAAD2RlYnRvckFzc2V0Q29kZQQAAAAJbGVuZGVkQW10CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAAabGVuZGVkQW1vdW50QnlBc3NldENvZGVLZXkJAAEsAAAAAgIAAAANTm8gZGVidHMgZm9yIAUAAAAPZGVidG9yQXNzZXRDb2RlAwkBAAAAAiE9AAAAAgUAAAALZGVidEFzc2V0SWQFAAAADWRlYnRQbXRBc3NldDAJAAACAAAAAQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAA0aW52YWxpZCBkZWJ0IGFzc2V0IGlkIGluIHRoZSBmaXJzdCBwYXltZXQ6IGV4cGVjdGVkPQkAAlgAAAABBQAAAAtkZWJ0QXNzZXRJZAIAAAAIIGFjdHVhbD0JAAJYAAAAAQUAAAANZGVidFBtdEFzc2V0MAMJAQAAAAIhPQAAAAIFAAAAC2Jhc2VBc3NldElkBQAAAA1iYXNlUG10QXNzZXQxCQAAAgAAAAEJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAANmludmFsaWQgYmFzZSBhc3NldCBpZCBpbiB0aGUgc2Vjb25kIHBheW1lbnQ6IGV4cGVjdGVkPQkAAlgAAAABBQAAAAtiYXNlQXNzZXRJZAIAAAAIIGFjdHVhbD0JAAJYAAAAAQUAAAANYmFzZVBtdEFzc2V0MQMJAQAAAAIhPQAAAAIIBQAAAAhkZWJ0UG10MAAAAAZhbW91bnQIBQAAAAhiYXNlUG10MQAAAAZhbW91bnQJAAACAAAAAQIAAAA/Zmlyc3QgcGF5bWVudCBhbW91bnQgZG9lc24ndCBtYXRjaCB0byB0aGUgc2Vjb25kIHBheW1lbnQgYW1vdW50AwkAAGcAAAACAAAAAAAAAAAABQAAAAlsZW5kZWRBbXQJAAACAAAAAQkAASwAAAACAgAAACdsZW5kZWRBbXQgaXMgbGVzcyB0aGVuIHplcm86IGxlbmRlZEFtdD0JAAGkAAAAAQUAAAAJbGVuZGVkQW10AwkAAGcAAAACAAAAAAAAAAAACAUAAAAIZGVidFBtdDAAAAAGYW1vdW50CQAAAgAAAAEJAAEsAAAAAgIAAAA1YXR0YWNoZWQgcGF5bWVudCBtdXN0IGJlIGdyZWF0ZXIgdGhlbiAwOiBwbXQwLmFtb3VudD0JAAGkAAAAAQgFAAAACGRlYnRQbXQwAAAABmFtb3VudAMJAABmAAAAAggFAAAACGRlYnRQbXQwAAAABmFtb3VudAUAAAAJbGVuZGVkQW10CQAAAgAAAAEJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAANGF0dGFjaGVkIHBheW1lbnQgaXMgZ3JhdGVyIHRoYW4gcmVxdWlyZWQ6IHBtdEFtb3VudD0JAAGkAAAAAQgFAAAACGRlYnRQbXQwAAAABmFtb3VudAIAAAALIGxlbmRlZEFtdD0JAAGkAAAAAQUAAAAJbGVuZGVkQW10BAAAABZ0b3RhbExlbmRlZEF0T3RoZXJBY2NzCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMJAQAAABlrZXlUb3RhbExlbmRlZEF0T3RoZXJBY2NzAAAAAAAAAAAAAAAAAAQAAAAObGVuZGVkQW10QWZ0ZXIJAABlAAAAAgUAAAAJbGVuZGVkQW10CAUAAAAIZGVidFBtdDAAAAAGYW1vdW50CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABpsZW5kZWRBbW91bnRCeUFzc2V0Q29kZUtleQUAAAAObGVuZGVkQW10QWZ0ZXIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABlrZXlUb3RhbExlbmRlZEF0T3RoZXJBY2NzAAAAAAkAAGUAAAACBQAAABZ0b3RhbExlbmRlZEF0T3RoZXJBY2NzCAUAAAAIZGVidFBtdDAAAAAGYW1vdW50CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAAEsAAAAAgIAAAAWJXMlc19fcmViYWxhbmNlVHJhY2VfXwkAAlgAAAABCAUAAAABaQAAAA10cmFuc2FjdGlvbklkCQEAAAAXYXNzZXREYXRhUmViYWxhbmNlVHJhY2UAAAAFBQAAAA9kZWJ0b3JBc3NldENvZGUFAAAACGRlYnRQbXQwBQAAAAhiYXNlUG10MQUAAAAJbGVuZGVkQW10BQAAAA5sZW5kZWRBbXRBZnRlcgUAAAADbmlsAAAAAWkBAAAACHdpdGhkcmF3AAAAAwAAAA5hY2NvdW50QWRkcmVzcwAAAAx1bmxvY2tIZWlnaHQAAAADaWR4BAAAAA9hY2NPcGVyYXRpb25LZXkJAQAAABNrZXlBY2NvdW50T3BlcmF0aW9uAAAAAwUAAAAMdW5sb2NrSGVpZ2h0BQAAAA5hY2NvdW50QWRkcmVzcwIAAAAHUEVORElORwQAAAAVYWNjT3BlcmF0aW9uRGF0YUFycmF5CQEAAAAcYXNzZXRSZWFkU3dhcERhdGFBcnJheU9yRmFpbAAAAAEFAAAAD2FjY09wZXJhdGlvbktleQQAAAAIYW1vdW50SW4JAQAAAA1wYXJzZUludFZhbHVlAAAAAQkAAZEAAAACBQAAABVhY2NPcGVyYXRpb25EYXRhQXJyYXkFAAAAFElkeE9wZXJhdGlvbkFtb3VudEluBAAAAAdhc3NldEluCQABkQAAAAIFAAAAFWFjY09wZXJhdGlvbkRhdGFBcnJheQUAAAATSWR4T3BlcmF0aW9uQXNzZXRJbgQAAAAIYXNzZXRPdXQJAAGRAAAAAgUAAAAVYWNjT3BlcmF0aW9uRGF0YUFycmF5BQAAABRJZHhPcGVyYXRpb25Bc3NldE91dAMJAABmAAAAAgUAAAAMdW5sb2NrSGVpZ2h0BQAAAAZoZWlnaHQJAAACAAAAAQkAASwAAAACCQABLAAAAAICAAAADFBsZWFzZSB3YWl0IAkAAaQAAAABBQAAAAx1bmxvY2tIZWlnaHQCAAAAFyB0byB3aXRoZHJhdyB5b3VyIGZ1bmRzBAAAABBhY2NvdW50TG9ja2VkQW10BQAAAAhhbW91bnRJbgMJAABnAAAAAgAAAAAAAAAAAAUAAAAQYWNjb3VudExvY2tlZEFtdAkAAAIAAAABAgAAABFMb2NrZWRBbW91bnQgPD0gMAQAAAATYXNzZXRMb2NrZWRUb3RhbEtleQkBAAAAE2tleUFzc2V0TG9ja2VkVG90YWwAAAABCQABkQAAAAIFAAAAFWFjY09wZXJhdGlvbkRhdGFBcnJheQUAAAATSWR4T3BlcmF0aW9uQXNzZXRJbgQAAAAUY3VyckFzc2V0TG9ja2VkVG90YWwJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAABNhc3NldExvY2tlZFRvdGFsS2V5CQABLAAAAAIJAAEsAAAAAgIAAAAgU3RhdGUgY29udGFpbnMgc2VsbEFzc2V0UmVxdWVzdD0FAAAAD2FjY09wZXJhdGlvbktleQIAAAATIEJVVCBubyB0b3RhbExvY2tlZAQAAAAJaWR4SGVpZ2h0CQEAAAAXY29udHJvbEFjY1JlYWRJZHhIZWlnaHQAAAABBQAAAANpZHgEAAAADXByZXZJZHhIZWlnaHQJAQAAABdjb250cm9sQWNjUmVhZElkeEhlaWdodAAAAAEJAABlAAAAAgUAAAADaWR4AAAAAAAAAAABBAAAAAdjdXJySWR4CQEAAAAbY29udHJvbEFjY1JlYWRDdXJySWR4T3JGYWlsAAAAAAMDAwkAAGYAAAACBQAAAANpZHgFAAAAB2N1cnJJZHgGCQAAZgAAAAIFAAAADHVubG9ja0hlaWdodAUAAAAJaWR4SGVpZ2h0BgMJAQAAAAIhPQAAAAIFAAAADXByZXZJZHhIZWlnaHQAAAAAAAAAAAAJAABnAAAAAgUAAAANcHJldklkeEhlaWdodAUAAAAMdW5sb2NrSGVpZ2h0BwkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAABdpbnZhbGlkIHByaWNlIGlkeDogaWR4PQkAAaQAAAABBQAAAANpZHgCAAAACSBjdXJySWR4PQkAAaQAAAABBQAAAAdjdXJySWR4AgAAAAsgaWR4SGVpZ2h0PQkAAaQAAAABBQAAAAlpZHhIZWlnaHQCAAAADiB1bmxvY2tIZWlnaHQ9CQABpAAAAAEFAAAADHVubG9ja0hlaWdodAIAAAAPIHByZXZJZHhIZWlnaHQ9CQABpAAAAAEFAAAADXByZXZJZHhIZWlnaHQEAAAAEHN5bnRoMmJhc2ljUHJpY2UJAQAAABtjb250cm9sQWNjUmVhZFByaWNlQnlIZWlnaHQAAAABBQAAAAlpZHhIZWlnaHQEAAAADGFzc2V0SW5CeXRlcwkAAlkAAAABBQAAAAdhc3NldEluBAAAAA0kdDAxODYyMzE5NDkzAwkAAAAAAAACBQAAAAxhc3NldEluQnl0ZXMFAAAAC2Jhc2VBc3NldElkBAAAAAhzeW50aEFtdAkAAGsAAAADBQAAAAhhbW91bnRJbgUAAAANcHJpY2VEZWNpbWFscwUAAAAQc3ludGgyYmFzaWNQcmljZQkABRYAAAAEBQAAAAhzeW50aEFtdAkBAAAAB1JlaXNzdWUAAAADBQAAAAtkZWZvQXNzZXRJZAUAAAAIc3ludGhBbXQGCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABBQAAAA5hY2NvdW50QWRkcmVzcwUAAAAIc3ludGhBbXQFAAAAC2RlZm9Bc3NldElkCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAADmtleVVjb2xsYXRlcmFsAAAAAAkAAGQAAAACBQAAAAt1Y29sbGF0ZXJhbAUAAAAIYW1vdW50SW4DCQAAAAAAAAIFAAAADGFzc2V0SW5CeXRlcwUAAAALZGVmb0Fzc2V0SWQEAAAACGJhc2ljQW10CQAAawAAAAMFAAAACGFtb3VudEluBQAAABBzeW50aDJiYXNpY1ByaWNlBQAAAA1wcmljZURlY2ltYWxzBAAAAA5uZXdVY29sbGF0ZXJhbAkAAGUAAAACBQAAAAt1Y29sbGF0ZXJhbAUAAAAIYmFzaWNBbXQJAAUWAAAABAUAAAAIYmFzaWNBbXQJAQAAAARCdXJuAAAAAgUAAAALYmFzZUFzc2V0SWQFAAAACGJhc2ljQW10CQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABBQAAAA5hY2NvdW50QWRkcmVzcwUAAAAIYmFzaWNBbXQFAAAAC2Jhc2VBc3NldElkCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAADmtleVVjb2xsYXRlcmFsAAAAAAkAAGUAAAACBQAAAAt1Y29sbGF0ZXJhbAUAAAAIYmFzaWNBbXQJAAACAAAAAQkAASwAAAACAgAAABRVbnN1cHBvcnRlZCBhc3NldEluPQUAAAAHYXNzZXRJbgQAAAAJYW1vdW50T3V0CAUAAAANJHQwMTg2MjMxOTQ5MwAAAAJfMQQAAAALYnVybk9ySXNzdWUIBQAAAA0kdDAxODYyMzE5NDkzAAAAAl8yBAAAABR0cmFuc2ZlclN5bnRoT3JCYXNpYwgFAAAADSR0MDE4NjIzMTk0OTMAAAACXzMEAAAAEHVjb2xsYXRlcmFsRW50cnkIBQAAAA0kdDAxODYyMzE5NDkzAAAAAl80AwkAAGYAAAACAAAAAAAAAAAACQAAZQAAAAIFAAAAFGN1cnJBc3NldExvY2tlZFRvdGFsBQAAABBhY2NvdW50TG9ja2VkQW10CQAAAgAAAAEJAAEsAAAAAgkAASwAAAACAgAAABRJbnZhbGlkIGRhdGEgc3RhdGU6IAUAAAATYXNzZXRMb2NrZWRUb3RhbEtleQIAAAAMIGxlc3MgdGhlbiAwCQAETQAAAAIJAARNAAAAAgkABE0AAAACCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABNhc3NldExvY2tlZFRvdGFsS2V5CQAAZQAAAAIFAAAAFGN1cnJBc3NldExvY2tlZFRvdGFsBQAAABBhY2NvdW50TG9ja2VkQW10CQAETAAAAAIJAQAAAAtEZWxldGVFbnRyeQAAAAEFAAAAD2FjY09wZXJhdGlvbktleQkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAATa2V5QWNjb3VudE9wZXJhdGlvbgAAAAMFAAAADHVubG9ja0hlaWdodAUAAAAOYWNjb3VudEFkZHJlc3MCAAAACEZJTklTSEVECQEAAAAWYXNzZXREYXRhU3dhcE9wZXJhdGlvbgAAAAcFAAAACGFtb3VudEluBQAAAAdhc3NldEluBQAAABBzeW50aDJiYXNpY1ByaWNlBQAAAAlhbW91bnRPdXQFAAAACGFzc2V0T3V0AAAAAAAAAAAAAAAAAAAAAAAABQAAAANuaWwFAAAAC2J1cm5Pcklzc3VlBQAAABR0cmFuc2ZlclN5bnRoT3JCYXNpYwUAAAAQdWNvbGxhdGVyYWxFbnRyeQAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAEAAAAByRtYXRjaDAFAAAAAnR4AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABdJbnZva2VTY3JpcHRUcmFuc2FjdGlvbgQAAAADaW52BQAAAAckbWF0Y2gwAwkBAAAAAiE9AAAAAggFAAAAA2ludgAAAAhmdW5jdGlvbgIAAAAOcmViYWxhbmNlRGVidHMJAAACAAAAAQIAAAAjb25seSByZWJhbGFuY2VEZWJ0cyBjYWxsIGlzIGFsbG93ZWQDCQEAAAACIT0AAAACCQABkQAAAAIJAQAAABxmYWN0b3J5UmVhZEFzc2V0Q2ZnQnlBZGRyZXNzAAAAAQkABCUAAAABCQAEJAAAAAEIBQAAAANpbnYAAAAEZEFwcAUAAAASSWR4RGVmb0Fzc2V0U3RhdHVzAgAAAAZJU1NVRUQJAAACAAAAAQIAAAAZb25seSBkZWZvIGRhcHAgaXMgYWxsb3dlZAMJAABmAAAAAggFAAAAA2ludgAAAANmZWUJAABoAAAAAgAAAAAAAAADhAAAAAAAAAAD6AkAAAIAAAABCQABLAAAAAICAAAAKGZlZSBhbW91bnQgaXMgZ3JlYXRlciB0aGFuIG1heCBhbGxvd2VkOiAJAAGkAAAAAQgFAAAAA2ludgAAAANmZWUDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA2ludgAAAApmZWVBc3NldElkCQAAAgAAAAECAAAAI29ubHkgV2F2ZXMgaXMgYWxsb3dlZCBhcyBmZWVBc3NldElkBgkAAfQAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAAIBQAAAAJ0eAAAAA9zZW5kZXJQdWJsaWNLZXnZqYEL" + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + tree, err := Parse(src) + require.NoError(t, err) + tree = MustExpand(tree) + require.True(t, tree.Expanded) + _, err = CompileTree("", tree) + require.NoError(t, err) +} + +func TestPropertyAssignment(t *testing.T) { + /* + let owner = Address(base58'3MpENPBGgEAefMN27XvegNEbjAyohkGueii') + func a(addr: Address) = if addr == owner then (nil, "OWNER") else ([StringEntry("CLIENT", addr.toString())], "CLIENT") + + @Callable(i) + func call() = { + a(i.caller)._1 + } + */ + source := "AAIEAAAAAAAAAAQIAhIAAAAAAgAAAAAFb3duZXIJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVQDdVnTDlsUNa8Yx+PtFt6k/zbLY1cIbJcBAAAAAWEAAAABAAAABGFkZHIDCQAAAAAAAAIFAAAABGFkZHIFAAAABW93bmVyCQAFFAAAAAIFAAAAA25pbAIAAAAFT1dORVIJAAUUAAAAAgkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACAgAAAAZDTElFTlQJAAQlAAAAAQUAAAAEYWRkcgUAAAADbmlsAgAAAAZDTElFTlQAAAABAAAAAWkBAAAABGNhbGwAAAAACAkBAAAAAWEAAAABCAUAAAABaQAAAAZjYWxsZXIAAAACXzEAAAAATkiWqg==" + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + tree, err := Parse(src) + require.NoError(t, err) + tree = MustExpand(tree) + require.True(t, tree.Expanded) + _, err = CompileTree("", tree) + require.NoError(t, err) +} diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index a93a07f7b6..d033f51943 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -62,6 +62,9 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "105": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, "/", nodes, f) }, + "106": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "%", nodes, f) + }, "200": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "size", nodes, f) }, @@ -101,18 +104,30 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "600": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "toBase58String", nodes, f) }, + "601": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "fromBase58String", nodes, f) + }, "604": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "fromBase64String", nodes, f) }, "2": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "throw", nodes, f) }, + "1100": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "::", nodes, f) + }, "1050": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "getInteger", nodes, f) }, + "1051": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "getBoolean", nodes, f) + }, "1052": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "getBinary", nodes, f) }, + "1053": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "getString", nodes, f) + }, "1201": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "toInt", nodes, f) }, @@ -170,10 +185,14 @@ func detree(s *strings.Builder, tree Node) { s.WriteString(" } ") detree(s, n.Block) case *AssignmentNode: - s.WriteString(fmt.Sprintf("let %s = { ", n.Name)) - detree(s, n.Expression) - s.WriteString(" }; ") - detree(s, n.Block) + if n.Name == "$match0" { + decompileMatch(s, n) + } else { + s.WriteString(fmt.Sprintf("let %s = { ", n.Name)) + detree(s, n.Expression) + s.WriteString(" }; ") + detree(s, n.Block) + } case *ConditionalNode: s.WriteString("if (") detree(s, n.Condition) @@ -207,3 +226,25 @@ func detree(s *strings.Builder, tree Node) { panic(fmt.Sprintf("unknown type %T", n)) } } + +func decompileMatch(s *strings.Builder, a *AssignmentNode) { + s.WriteString("match ") + detree(s, a.Expression) + s.WriteString(" { ") + n := a.Block + for { + v, ok := n.(*ConditionalNode) + if !ok { + break + } + s.WriteString("case a: ") + s.WriteString(v.Condition.(*FunctionCallNode).Arguments[1].(*StringNode).Value) + s.WriteString(" => { ") + detree(s, v.TrueExpression.(*AssignmentNode).Block) + s.WriteString(" } ") + n = v.FalseExpression + } + s.WriteString("case _ => { ") + detree(s, n) + s.WriteString(" }") +} diff --git a/pkg/ride/decompiler_test.go b/pkg/ride/decompiler_test.go new file mode 100644 index 0000000000..08a9a75fca --- /dev/null +++ b/pkg/ride/decompiler_test.go @@ -0,0 +1,40 @@ +package ride + +import ( + "github.com/stretchr/testify/require" + + "testing" +) + +func TestDecompiler(t *testing.T) { + t.Run("check match", func(t *testing.T) { + source := `AAIDAAAAAAAAAAIIAQAAAAEBAAAADmdldE51bWJlckJ5S2V5AAAAAQAAAANrZXkEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAADa2V5AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAAWEFAAAAByRtYXRjaDAFAAAAAWEAAAAAAAAAAAAAAAAAAAAAAFURfiw=` + tree, err := ParseB64(source) + require.NoError(t, err) + + require.Equal(t, + "func getNumberByKey(key) { match getInteger(this,key) { case a: Int => { a } case _ => { 0 } }", + DecompileTree(tree), + ) + }) + t.Run("check match multiple choices", func(t *testing.T) { + /* + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# CONTENT_TYPE DAPP #-} + func getNumberByKey (key: Transaction) = match key { + case a: BurnTransaction => 1 + case a: IssueTransaction => 2 + case _ => 0 + } + */ + source := `AAIDAAAAAAAAAAIIAQAAAAEBAAAADmdldE51bWJlckJ5S2V5AAAAAQAAAANrZXkEAAAAByRtYXRjaDAFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAPQnVyblRyYW5zYWN0aW9uBAAAAAFhBQAAAAckbWF0Y2gwAAAAAAAAAAABAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABBJc3N1ZVRyYW5zYWN0aW9uBAAAAAFhBQAAAAckbWF0Y2gwAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAADkJzDk` + tree, err := ParseB64(source) + require.NoError(t, err) + + require.Equal(t, + "func getNumberByKey(key) { match key { case a: BurnTransaction => { 1 } case a: IssueTransaction => { 2 } case _ => { 0 } }", + DecompileTree(tree), + ) + }) +} diff --git a/pkg/ride/deserializer.go b/pkg/ride/deserializer.go index f230ba18d6..2b069de8d5 100644 --- a/pkg/ride/deserializer.go +++ b/pkg/ride/deserializer.go @@ -32,6 +32,14 @@ func (a *Deserializer) Uint16() (uint16, error) { return binary.BigEndian.Uint16(b), nil } +func (a *Deserializer) Uint32() (uint32, error) { + b, err := a.readn(4) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint32(b), nil +} + func (a *Deserializer) Byte() (byte, error) { b, err := a.readn(1) if err != nil { @@ -56,7 +64,7 @@ func (a *Deserializer) Bool() (bool, error) { } func (a *Deserializer) Bytes() ([]byte, error) { - ln, err := a.Uint16() + ln, err := a.Uint32() if err != nil { return nil, err } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index ff684b5c58..a3f44ec3aa 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -12,7 +12,7 @@ type Executable struct { position int // Non-default value assumes interrupted evaluation. ByteCode []byte EntryPoints map[string]Entrypoint - References map[uniqueid]point + References map[uniqueID]point } func (a *Executable) HasVerifier() bool { @@ -225,7 +225,7 @@ func DeserializeExecutable(source []byte) (*Executable, error) { if err != nil { return nil, err } - references := make(map[uniqueid]point, size) + references := make(map[uniqueID]point, size) for i := uint16(0); i < size; i++ { id, err := d.Uint16() if err != nil { diff --git a/pkg/ride/parser.go b/pkg/ride/parser.go index 20e4542efa..b59cca1d0a 100644 --- a/pkg/ride/parser.go +++ b/pkg/ride/parser.go @@ -3,6 +3,7 @@ package ride import ( "bytes" sh256 "crypto/sha256" + "encoding/base64" "encoding/binary" "strconv" @@ -46,6 +47,14 @@ func Parse(source []byte) (*Tree, error) { return p.parse() } +func ParseB64(source string) (*Tree, error) { + src, err := base64.StdEncoding.DecodeString(source) + if err != nil { + return nil, err + } + return Parse(src) +} + type parser struct { r *bytes.Reader seenBlockV2 bool diff --git a/pkg/ride/serializer.go b/pkg/ride/serializer.go index d3b0042eef..09755e667f 100644 --- a/pkg/ride/serializer.go +++ b/pkg/ride/serializer.go @@ -14,7 +14,6 @@ const ( sInt byte = 103 sBytes byte = 105 sString byte = 106 - sPoint byte = 107 sMap byte = 108 sNoValue byte = 109 sAddress byte = 110 @@ -58,6 +57,12 @@ func (a *Serializer) Uint16(v uint16) { a.b.Write(b) } +func (a *Serializer) Uint32(v uint32) { + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, v) + a.b.Write(b) +} + func (a *Serializer) Bool(v bool) { if v { a.b.WriteByte(sTrue) @@ -66,11 +71,6 @@ func (a *Serializer) Bool(v bool) { } } -func (a *Serializer) Point(p point) { - a.b.WriteByte(sPoint) - a.Uint16(p.position) -} - func (a *Serializer) Byte(b byte) { a.b.WriteByte(b) } @@ -85,10 +85,10 @@ func (a *Serializer) Type(t byte) error { } func (a *Serializer) Bytes(v []byte) error { - if len(v) > math.MaxUint16 { + if len(v) > math.MaxUint32 { return errors.New("bytes length overflow") } - a.Uint16(uint16(len(v))) + a.Uint32(uint32(len(v))) a.b.Write(v) return nil } @@ -116,10 +116,10 @@ func (a *Serializer) RideUnit() error { } func (a *Serializer) String(v string) error { - if len(v) > math.MaxUint16 { + if len(v) > math.MaxUint32 { return errors.New("bytes length overflow") } - a.Uint16(uint16(len(v))) + a.Uint32(uint32(len(v))) a.b.Write([]byte(v)) return nil } diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index fea2e60694..949d16f5d8 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -3558,7 +3558,7 @@ func TestTreeShadowedVariable2(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) tree = MustExpand(tree) - require.Equal(t, "(let height$yy = { height }; let height$xx = { height$yy }; height$xx == 1)", DecompileTree(tree)) + require.Equal(t, "(let height@yy = { height }; let height@xx = { height@yy }; height@xx == 1)", DecompileTree(tree)) result, err := CallTreeVerifier(defaultEnv, tree) require.NoError(t, err) diff --git a/pkg/ride/tree_expand.go b/pkg/ride/tree_expand.go index 9f2e9134e8..0551a03644 100644 --- a/pkg/ride/tree_expand.go +++ b/pkg/ride/tree_expand.go @@ -7,6 +7,8 @@ import ( "github.com/pkg/errors" ) +const expandPrefix = "@" + type expandScope struct { im *im.Map } @@ -83,7 +85,7 @@ func Expand(t *Tree) (*Tree, error) { declarations = append(declarations, expand(scope, f, newNameReplacements())) continue } - v2 := cloneFuncDecl(v, expand(scope, v.Body, newNameReplacements().addAll("$"+v.Name, v.Arguments)), nil) + v2 := cloneFuncDecl(v, expand(scope, v.Body, newNameReplacements().addAll(expandPrefix+v.Name, v.Arguments)), nil) scope = scope.add(v.Name, v2) } functions := make([]Node, 0, len(t.Functions)) @@ -132,7 +134,7 @@ func expand(scope expandScope, node Node, replacements nameReplacements) Node { root := f.Body for i := len(v.Arguments) - 1; i >= 0; i-- { root = &AssignmentNode{ - Name: fmt.Sprintf("%s$%s", f.Arguments[i], f.Name), + Name: fmt.Sprintf("%s%s%s", f.Arguments[i], expandPrefix, f.Name), Expression: expand(scope, v.Arguments[i], replacements), Block: root, } @@ -149,7 +151,7 @@ func expand(scope expandScope, node Node, replacements nameReplacements) Node { case *FunctionDeclarationNode: - body := expand(scope, v.Body, replacements.addAll("$"+v.Name, v.Arguments)) + body := expand(scope, v.Body, replacements.addAll(expandPrefix+v.Name, v.Arguments)) v2 := cloneFuncDecl(v, body, nil) block := expand(scope.add(v.Name, v2), v.Block, replacements) return block diff --git a/pkg/ride/tree_expand_test.go b/pkg/ride/tree_expand_test.go index bb911057ce..cbd69ee47e 100644 --- a/pkg/ride/tree_expand_test.go +++ b/pkg/ride/tree_expand_test.go @@ -35,7 +35,7 @@ func TestTreeExpandWithArguments(t *testing.T) { require.Equal(t, lines( `let z = { 5 };`, - `@i\nfunc f1(sessionId,rsaSign) { let x = { let v$f2 = { "e" }; value(getInteger(this,v$f2)) }; WriteSet(nil) }`, + `@i\nfunc f1(sessionId,rsaSign) { let x = { let v@f2 = { "e" }; value(getInteger(this,v@f2)) }; WriteSet(nil) }`, ), DecompileTree(tree2), ) @@ -66,7 +66,7 @@ func TestTreeExpandAsArgument(t *testing.T) { tree2, _ := Expand(tree) require.Equal(t, - `@i\nfunc f1() { WriteSet(1100(DataEntry("key",5),nil)) }`, + `@i\nfunc f1() { WriteSet((DataEntry("key",5) :: nil)) }`, DecompileTree(tree2), ) } @@ -103,7 +103,7 @@ func TestTreeExpandWithNamesIntersection(t *testing.T) { tree2, _ := Expand(tree) require.Equal(t, - `@i\nfunc callback() { let x = { let v$call = { 0 }; 10 }; WriteSet(1100(DataEntry("key",5),nil)) }`, + `@i\nfunc callback() { let x = { let v@call = { 0 }; 10 }; WriteSet((DataEntry("key",5) :: nil)) }`, DecompileTree(tree2), ) } @@ -130,7 +130,7 @@ func TestTreeExpand(t *testing.T) { tree2, _ := Expand(tree) require.Equal(t, - `(let inc$call = { 2 }; let v$inc = { inc$call }; (v$inc + 1) == 3)`, + `(let inc@call = { 2 }; let v@inc = { inc@call }; (v@inc + 1) == 3)`, DecompileTree(tree2), ) rs, err := CallTreeVerifier(nil, tree2) diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 567f163f6b..ac46f0de6c 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -35,15 +35,11 @@ func (m *vm) run() (rideType, error) { if err != nil { return nil, err } - case OpJump: - pos := m.arg16() - m.jmps = append(m.jmps, m.ip) - m.ip = pos case OpJumpIfFalse: - posTrue := m.arg16() - posFalse := m.arg16() - posNext := m.arg16() + posTrue := m.arg32() + posFalse := m.arg32() + posNext := m.arg32() m.jmps = append(m.jmps, posNext) val, err := m.pop() @@ -59,6 +55,7 @@ func (m *vm) run() (rideType, error) { } else { m.ip = posFalse } + case OpProperty: prop, err := m.pop() if err != nil { @@ -77,10 +74,6 @@ func (m *vm) run() (rideType, error) { return nil, errors.Wrap(err, "vm OpProperty") } m.push(v) - case OpCall: - pos := m.arg16() - m.jmps = append(m.jmps, m.ip) - m.ip = pos case OpExternalCall: // Before calling external function all parameters must be evaluated and placed on stack @@ -119,6 +112,7 @@ func (m *vm) run() (rideType, error) { return res, nil } m.push(res) + case OpReturn: l := len(m.jmps) if l == 0 { @@ -133,13 +127,6 @@ func (m *vm) run() (rideType, error) { } m.ip, m.jmps = m.jmps[l-1], m.jmps[:l-1] - case OpSetArg: - from := m.uint16() - to := m.uint16() - // for debug purpose - x := m.ref[from] - _ = x - m.ref[to] = m.ref[from] case OpCache: refID := m.uint16() if refID < 200 { @@ -153,6 +140,7 @@ func (m *vm) run() (rideType, error) { point := m.ref[refID] point.value = value m.ref[refID] = point + case OpClearCache: refID := m.uint16() point, ok := m.ref[refID] @@ -192,7 +180,7 @@ func (m *vm) run() (rideType, error) { } m.push(rs) } else { - if m.ip == int(point.position)+3 { + if m.ip == int(point.position)+5 { return nil, errors.Errorf("infinity loop detected on iteration %d", m.numOperations) } m.jmps = append(m.jmps, m.ip) @@ -200,13 +188,13 @@ func (m *vm) run() (rideType, error) { } default: - return nil, errors.Errorf("unknown code %#x, at iteration %d", op, m.numOperations) + return nil, errors.Errorf("unknown code %#x, instruction pointer %d, at iteration %d", op, m.ip, m.numOperations) } } return nil, errors.New("broken code") } -func (m *vm) push(v rideType) constid { +func (m *vm) push(v rideType) constID { m.stack = append(m.stack, v) return uint16(len(m.stack) - 1) } @@ -231,6 +219,13 @@ func (m *vm) arg16() int { return int(res) } +func (m *vm) arg32() int { + //TODO: add check + res := binary.BigEndian.Uint32(m.code[m.ip : m.ip+4]) + m.ip += 4 + return int(res) +} + func (m *vm) uint16() uint16 { //TODO: add check res := binary.BigEndian.Uint16(m.code[m.ip : m.ip+2]) diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 0672ad0165..3ba909f393 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -162,15 +162,11 @@ func (ss *scriptsStorage) setScript(scriptType blockchainEntity, key []byte, rec var exe *ride.Executable if len(record.script) > 0 { if len(record.bytecode) == 0 { - p, err := scriptBytesToTree(record.script) + tree, err := scriptBytesToTree(record.script) if err != nil { return err } - //expandedTree, err := ride.Expand(p) - //if err != nil { - // return err - //} - exe, err = ride.CompileTree("scriptsStorage setScript "+txID, p) + exe, err = ride.CompileTree("scriptsStorage setScript "+txID, tree) if err != nil { return err } @@ -252,8 +248,8 @@ func (ss *scriptsStorage) scriptExecutableFromRecordBytes(recordBytes []byte) (* // Empty script = no script. return nil, crypto.PublicKey{}, proto.ErrNotFound } - tree, err := scriptBytesToExecutable(record.bytecode) - return tree, record.pk, err + exe, err := scriptBytesToExecutable(record.bytecode) + return exe, record.pk, err } func (ss *scriptsStorage) newestScriptAstByKey(key []byte, filter bool) (*ride.Tree, error) { @@ -270,8 +266,8 @@ func (ss *scriptsStorage) newestBytecodeByKey(key []byte, filter bool) (*ride.Ex if err != nil { return nil, err } - tree, _, err := ss.scriptExecutableFromRecordBytes(recordBytes) - return tree, err + exe, _, err := ss.scriptExecutableFromRecordBytes(recordBytes) + return exe, err } func (ss *scriptsStorage) scriptTreeByKey(key []byte, filter bool) (*ride.Tree, error) { @@ -472,11 +468,11 @@ func (ss *scriptsStorage) newestScriptByAddr(addr proto.Address, filter bool) (* func (ss *scriptsStorage) newestBytecodeByAddr(addr proto.Address, filter bool) (*ride.Executable, error) { key := accountScriptKey{addr} keyBytes := key.bytes() - tree, err := ss.newestBytecodeByKey(keyBytes, filter) + exe, err := ss.newestBytecodeByKey(keyBytes, filter) if err != nil { return nil, err } - return tree, nil + return exe, nil } func (ss *scriptsStorage) newestScriptPKByAddr(addr proto.Address, filter bool) (crypto.PublicKey, error) {