From f7bff52116818482b7b15011224f905052975c54 Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 23 Oct 2020 12:54:29 +0300 Subject: [PATCH 01/55] Stateful compiler. --- pkg/ride/compiler2.go | 81 ++++++++++++++++++ pkg/ride/compiler2_test.go | 122 +++++++++++++++++++++++++++ pkg/ride/compiler_fsm.go | 63 ++++++++++++++ pkg/ride/compiler_fsm_assigment.go | 75 ++++++++++++++++ pkg/ride/compiler_fsm_call.go | 73 ++++++++++++++++ pkg/ride/compiler_fsm_conditional.go | 63 ++++++++++++++ pkg/ride/compiler_fsm_definitions.go | 80 ++++++++++++++++++ pkg/ride/compiler_helpers.go | 120 ++++++++++++++++++++++++++ pkg/ride/compiler_helpers_test.go | 21 +++++ pkg/ride/executable.go | 24 ++++++ pkg/ride/vm.go | 53 ++++++++---- pkg/ride/vm_test.go | 82 +++++++++--------- 12 files changed, 800 insertions(+), 57 deletions(-) create mode 100644 pkg/ride/compiler2.go create mode 100644 pkg/ride/compiler2_test.go create mode 100644 pkg/ride/compiler_fsm.go create mode 100644 pkg/ride/compiler_fsm_assigment.go create mode 100644 pkg/ride/compiler_fsm_call.go create mode 100644 pkg/ride/compiler_fsm_conditional.go create mode 100644 pkg/ride/compiler_fsm_definitions.go create mode 100644 pkg/ride/compiler_helpers.go create mode 100644 pkg/ride/compiler_helpers_test.go create mode 100644 pkg/ride/executable.go diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go new file mode 100644 index 0000000000..05c82f6496 --- /dev/null +++ b/pkg/ride/compiler2.go @@ -0,0 +1,81 @@ +package ride + +import "github.com/pkg/errors" + +func ccc(f Fsm, node Node) (Fsm, error) { + switch n := node.(type) { + case *AssignmentNode: + fsm, err := ccc(f.Assigment(n.Name), n.Expression) + if err != nil { + return fsm, err + } + return ccc(fsm.Return(), n.Block) + case *LongNode: + return f.Long(n.Value), nil + case *FunctionCallNode: + f = f.Call(n.Name, uint16(len(n.Arguments))) + for i := range n.Arguments { + f, err := ccc(f, n.Arguments[i]) + if err != nil { + return f, err + } + } + return f.Return(), nil + case *ReferenceNode: + return f.Reference(n.Name), nil + case *BooleanNode: + return f.Boolean(n.Value), nil + case *StringNode: + return f.String(n.Value), nil + case *BytesNode: + return f.Bytes(n.Value), nil + case *ConditionalNode: + f, err := ccc(f.Condition(), n.Condition) + if err != nil { + return f, err + } + f, err = ccc(f.TrueBranch(), n.TrueExpression) + if err != nil { + return f, err + } + f, err = ccc(f.FalseBranch(), n.FalseExpression) + if err != nil { + return f, err + } + return f.Return(), nil + case *FunctionDeclarationNode: + // TODO + fsm, err := ccc(f.Assigment(n.Name), n.Body) + if err != nil { + return fsm, err + } + return ccc(fsm.Return(), n.Block) + default: + return f, errors.Errorf("unknown type %T", node) + } +} + +func CompileSimpleScript(t *Tree) (*Executable, error) { + return compileSimpleScript(t.LibVersion, t.Verifier) +} + +func compileSimpleScript(libVersion int, node Node) (*Executable, error) { + fCheck, err := selectFunctionChecker(libVersion) + if err != nil { + return nil, err + } + b := newBuilder() + c := newConstants() + r := newReferences(nil) + + f := NewDefinitionsFsm(b, c, r, fCheck) + f, err = ccc(f, node) + if err != nil { + return nil, err + } + // Just to write `OpReturn` to bytecode. + f = f.Return() + + return f.(BuildExecutable).BuildExecutable(libVersion), nil + +} diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go new file mode 100644 index 0000000000..28826238fe --- /dev/null +++ b/pkg/ride/compiler2_test.go @@ -0,0 +1,122 @@ +package ride + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + //"github.com/wavesplatform/gowaves/pkg/proto" + //"github.com/wavesplatform/gowaves/pkg/types" +) + +func Test_ccc(t *testing.T) { + + version := 3 + + // let x = 5; 6 > x + ast := &AssignmentNode{ + Name: "x", + Expression: &LongNode{ + Value: 5, + }, + Block: &FunctionCallNode{ + Name: "102", // gt + Arguments: []Node{ + &LongNode{ + Value: 6, + }, + &ReferenceNode{ + Name: "x", + }, + }, + }, + } + rs, err := compileSimpleScript(version, ast) + + fSelect, err := selectFunctions(version) + require.NoError(t, err) + + v := vm{ + code: rs.ByteCode, + ip: int(rs.EntryPoints[""]), + constants: rs.Constants, + functions: fSelect, + } + + sr, err := v.run() + require.NoError(t, err) + + t.Log(sr) + +} + +func Test22(t *testing.T) { + //state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + // return testTransferWithProofs(), nil + //}} + //env := &MockRideEnvironment{ + // transactionFunc: testTransferObject, + // stateFunc: func() types.SmartState { + // return state + // }, + // schemeFunc: func() byte { + // return 'T' + // }, + //} + for _, test := range []struct { + comment string + source string + env RideEnvironment + res bool + }{ + //{`V1: true`, "AQa3b8tH", nil, true}, + //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, + //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, + //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, + //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, + //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, + {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, + //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, + //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + //{`false`, `AQfeYll6`, nil, false}, + //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, + //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, + //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, + //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, nil, true}, + //{`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==`, nil, true}, + //{`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, nil, true}, + } { + src, err := base64.StdEncoding.DecodeString(test.source) + require.NoError(t, err, test.comment) + + tree, err := Parse(src) + require.NoError(t, err, test.comment) + assert.NotNil(t, tree, test.comment) + + script, err := CompileSimpleScript(tree) + require.NoError(t, err, test.comment) + assert.NotNil(t, script, test.comment) + + res, err := script.Run(test.env) + require.NoError(t, err, test.comment) + assert.NotNil(t, res, test.comment) + r, ok := res.(ScriptResult) + assert.True(t, ok, test.comment) + assert.Equal(t, test.res, r.Result(), test.comment) + } +} diff --git a/pkg/ride/compiler_fsm.go b/pkg/ride/compiler_fsm.go new file mode 100644 index 0000000000..68531a23db --- /dev/null +++ b/pkg/ride/compiler_fsm.go @@ -0,0 +1,63 @@ +package ride + +import "fmt" + +type Fsm interface { + Assigment(name string) Fsm + Return() Fsm + Long(value int64) Fsm + Call(name string, argc uint16) Fsm + Reference(name string) Fsm + Boolean(v bool) Fsm + String(s string) Fsm + Condition() Fsm + TrueBranch() Fsm + FalseBranch() Fsm + Bytes(b []byte) Fsm +} + +type FunctionChecker func(string) (uint16, bool) + +type params struct { + // wrapper on bytes.Buffer with handy methods. + b *builder + // slice of constants. + c *constants + // relation of variables and it's offset. + r *references + // way to get function id. + f FunctionChecker +} + +func long(f Fsm, params params, value int64) Fsm { + index := params.c.put(rideInt(value)) + params.b.push(index) + return f +} + +func boolean(f Fsm, params params, value bool) Fsm { + params.b.bool(value) + return f +} + +func str(a Fsm, params params, s string) Fsm { + index := params.c.put(rideString(s)) + params.b.push(index) + return a +} + +// TODO: remove duplicate +func constant(a Fsm, params params, rideType rideType) Fsm { + index := params.c.put(rideType) + params.b.push(index) + return a +} + +func reference(f Fsm, params params, name string) Fsm { + pos, ok := params.r.get(name) + if !ok { + panic(fmt.Sprintf("reference %s not found", name)) + } + params.b.jump(pos) + return f +} diff --git a/pkg/ride/compiler_fsm_assigment.go b/pkg/ride/compiler_fsm_assigment.go new file mode 100644 index 0000000000..0f256c5356 --- /dev/null +++ b/pkg/ride/compiler_fsm_assigment.go @@ -0,0 +1,75 @@ +package ride + +// Assigment: let x = 5 +type AssigmentFsm struct { + params + prev Fsm + name string + offset uint16 +} + +func (a AssigmentFsm) Bytes(b []byte) Fsm { + return constant(a, a.params, rideBytes(b)) +} + +func (a AssigmentFsm) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a AssigmentFsm) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on AssigmentFsm") +} + +func (a AssigmentFsm) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on AssigmentFsm") +} + +func (a AssigmentFsm) String(s string) Fsm { + return constant(a, a.params, rideString(s)) +} + +func (a AssigmentFsm) Boolean(v bool) Fsm { + return boolean(a, a.params, v) +} + +func assigmentFsmTransition(prev Fsm, params params, name string) Fsm { + return newAssigmentFsm(prev, params, name) +} + +func newAssigmentFsm(prev Fsm, p params, name string) Fsm { + return AssigmentFsm{ + prev: prev, + params: params{ + b: p.b, + c: p.c, + f: p.f, + // Create new scope, so assigment in assigment can't affect global state. + r: newReferences(p.r), + }, + name: name, + offset: p.b.len(), + } +} + +func (a AssigmentFsm) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a AssigmentFsm) Return() Fsm { + a.b.ret() + // store reference on variable and it's offset. + a.r.set(a.name, a.offset) + return a.prev +} + +func (a AssigmentFsm) Long(value int64) Fsm { + return long(a, a.params, value) +} + +func (a AssigmentFsm) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a AssigmentFsm) Reference(name string) Fsm { + return reference(a, a.params, name) +} diff --git a/pkg/ride/compiler_fsm_call.go b/pkg/ride/compiler_fsm_call.go new file mode 100644 index 0000000000..fb512f33f8 --- /dev/null +++ b/pkg/ride/compiler_fsm_call.go @@ -0,0 +1,73 @@ +package ride + +import "fmt" + +// Function call +type CallFsm struct { + prev Fsm + params + name string + argc uint16 +} + +func (a CallFsm) Bytes(b []byte) Fsm { + return constant(a, a.params, rideBytes(b)) +} + +func (a CallFsm) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a CallFsm) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on CallFsm") +} + +func (a CallFsm) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on CallFsm") +} + +func (a CallFsm) String(s string) Fsm { + return str(a, a.params, s) +} + +func (a CallFsm) Boolean(v bool) Fsm { + return boolean(a, a.params, v) +} + +func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { + return newCallFsm(prev, params, name, argc) +} + +func newCallFsm(prev Fsm, params params, name string, argc uint16) Fsm { + return &CallFsm{ + prev: prev, + params: params, + name: name, + argc: argc, + } +} + +func (a CallFsm) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a CallFsm) Long(value int64) Fsm { + return long(a, a.params, value) +} + +func (a CallFsm) Return() Fsm { + n, ok := a.f(a.name) + if !ok { + panic(fmt.Sprintf("function names %s not found", a.name)) + } + a.b.externalCall(n, a.argc) + return a.prev +} + +func (a CallFsm) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a CallFsm) Reference(name string) Fsm { + return reference(a, a.params, name) +} diff --git a/pkg/ride/compiler_fsm_conditional.go b/pkg/ride/compiler_fsm_conditional.go new file mode 100644 index 0000000000..80efdcbb35 --- /dev/null +++ b/pkg/ride/compiler_fsm_conditional.go @@ -0,0 +1,63 @@ +package ride + +// If-else statement. +type ConditionalFsm struct { + params + prev Fsm + patchPosition uint16 +} + +func (a ConditionalFsm) Bytes(b []byte) Fsm { + return constant(a, a.params, rideBytes(b)) +} + +func conditionalTransition(prev Fsm, params params) Fsm { + return ConditionalFsm{ + prev: prev, + params: params, + } +} + +func (a ConditionalFsm) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a ConditionalFsm) TrueBranch() Fsm { + a.b.jpmIfFalse() + a.patchPosition = a.b.writeStub(2) + return a +} + +func (a ConditionalFsm) FalseBranch() Fsm { + a.b.patch(a.patchPosition, encode(a.b.len())) + return a +} + +func (a ConditionalFsm) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a ConditionalFsm) Return() Fsm { + a.b.ret() + return a.prev +} + +func (a ConditionalFsm) Long(value int64) Fsm { + return long(a, a.params, value) +} + +func (a ConditionalFsm) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a ConditionalFsm) Reference(name string) Fsm { + return reference(a, a.params, name) +} + +func (a ConditionalFsm) Boolean(v bool) Fsm { + return boolean(a, a.params, v) +} + +func (a ConditionalFsm) String(s string) Fsm { + return str(a, a.params, s) +} diff --git a/pkg/ride/compiler_fsm_definitions.go b/pkg/ride/compiler_fsm_definitions.go new file mode 100644 index 0000000000..5bb1c0fc4f --- /dev/null +++ b/pkg/ride/compiler_fsm_definitions.go @@ -0,0 +1,80 @@ +package ride + +// Initial state, contains only assigments and last expression. +// TODO chose better name +type DefinitionFsm struct { + params +} + +func (a DefinitionFsm) Bytes(b []byte) Fsm { + panic("Illegal call `Bytes` on `DefinitionFsm`") +} + +func (a DefinitionFsm) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a DefinitionFsm) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on DefinitionFsm") +} + +func (a DefinitionFsm) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on DefinitionFsm") +} + +func (a DefinitionFsm) String(s string) Fsm { + panic("Illegal call `String` on DefinitionFsm") +} + +type BuildExecutable interface { + BuildExecutable(version int) *Executable +} + +func NewDefinitionsFsm(b *builder, c *constants, r *references, f FunctionChecker) Fsm { + return &DefinitionFsm{ + params: params{ + b: b, + c: c, + r: r, + f: f, + }, + } +} + +func (a DefinitionFsm) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a DefinitionFsm) Return() Fsm { + a.b.ret() + return a +} + +func (a DefinitionFsm) Long(value int64) Fsm { + panic("Illegal call Long on DefinitionFsm") +} + +func (a DefinitionFsm) Call(name string, argc uint16) Fsm { + a.b.startPos() + return callTransition(a, a.params, name, argc) +} + +func (a DefinitionFsm) Reference(name string) Fsm { + a.b.startPos() + return reference(a, a.params, name) +} + +func (a DefinitionFsm) Boolean(v bool) Fsm { + a.b.startPos() + return boolean(a, a.params, v) +} + +func (a DefinitionFsm) BuildExecutable(version int) *Executable { + startAt, code := a.b.build() + return &Executable{ + LibVersion: version, + ByteCode: code, + Constants: a.c.constants(), + EntryPoints: map[string]uint16{"": startAt}, + } +} diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go new file mode 100644 index 0000000000..a6ff800586 --- /dev/null +++ b/pkg/ride/compiler_helpers.go @@ -0,0 +1,120 @@ +package ride + +import "bytes" + +type builder struct { + w *bytes.Buffer + startAt uint16 +} + +func newBuilder() *builder { + return &builder{ + w: new(bytes.Buffer), + } +} + +func (b *builder) writeStub(len int) (position uint16) { + position = uint16(b.w.Len()) + for i := 0; i < len; i++ { + b.w.WriteByte(0) + } + return position +} + +func (b *builder) push(uint162 uint16) { + b.w.WriteByte(OpPush) + b.w.Write(encode(uint162)) +} + +func (b *builder) bool(v bool) { + if v { + b.w.WriteByte(OpTrue) + } else { + b.w.WriteByte(OpFalse) + } +} + +func (b *builder) bytes() []byte { + return b.w.Bytes() +} + +func (b *builder) ret() { + b.w.WriteByte(OpReturn) +} + +func (b *builder) jump(uint162 uint16) { + b.w.WriteByte(OpJump) + b.w.Write(encode(uint162)) +} + +func (b *builder) patch(at uint16, val []byte) { + bts := b.w.Bytes()[at:] + for i := range val { + bts[i] = val[i] + } +} + +func (b *builder) len() uint16 { + return uint16(b.w.Len()) +} + +func (b *builder) externalCall(id uint16, argc uint16) { + b.w.WriteByte(OpExternalCall) + b.w.Write(encode(id)) + b.w.Write(encode(argc)) +} + +func (b *builder) startPos() { + b.startAt = uint16(b.w.Len()) +} + +func (b *builder) build() (uint16, []byte) { + return b.startAt, b.w.Bytes() +} + +func (b *builder) jpmIfFalse() { + b.w.WriteByte(OpJumpIfFalse) +} + +type constants struct { + values []rideType +} + +func newConstants() *constants { + return &constants{} +} + +func (a *constants) put(value rideType) uint16 { + a.values = append(a.values, value) + return uint16(len(a.values) - 1) +} + +func (a *constants) constants() []rideType { + return a.values +} + +type references struct { + prev *references + refs map[string]uint16 +} + +func newReferences(prev *references) *references { + return &references{ + prev: prev, + refs: make(map[string]uint16), + } +} + +func (a *references) get(name string) (uint16, bool) { + if a == nil { + return 0, false + } + if offset, ok := a.refs[name]; ok { + return offset, ok + } + return a.prev.get(name) +} + +func (a *references) set(name string, offset uint16) { + a.refs[name] = offset +} diff --git a/pkg/ride/compiler_helpers_test.go b/pkg/ride/compiler_helpers_test.go new file mode 100644 index 0000000000..d71f3756b8 --- /dev/null +++ b/pkg/ride/compiler_helpers_test.go @@ -0,0 +1,21 @@ +package ride + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// Check that patches correctly. +func TestBuilderPatch(t *testing.T) { + b := newBuilder() + + b.bool(true) + patchStart := b.writeStub(2) + b.bool(true) + + b.patch(patchStart, []byte{0xff, 0xff}) + + require.Equal(t, b.bytes(), []byte{OpTrue, 0xff, 0xff, OpTrue}) + +} diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go new file mode 100644 index 0000000000..0bf3ff7ea2 --- /dev/null +++ b/pkg/ride/executable.go @@ -0,0 +1,24 @@ +package ride + +type Executable struct { + LibVersion int + ByteCode []byte + Constants []rideType + EntryPoints map[string]uint16 +} + +func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { + fSelect, err := selectFunctions(a.LibVersion) + if err != nil { + return nil, err + } + + v := vm{ + code: a.ByteCode, + ip: int(a.EntryPoints[""]), + constants: a.Constants, + functions: fSelect, + } + + return v.run() +} diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 1cf82c2823..dbd1712ea5 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -45,7 +45,7 @@ func (m *vm) run() (RideResult, error) { if m.calls != nil { m.calls = m.calls[0:0] } - m.ip = 0 + //m.ip = 0 for m.ip < len(m.code) { op := m.code[m.ip] m.ip++ @@ -63,10 +63,16 @@ func (m *vm) run() (RideResult, error) { m.push(rideBoolean(false)) case OpJump: pos := m.arg16() + current := m.ip m.ip = pos + m.calls = append(m.calls, newExpressionFrame(current)) case OpJumpIfFalse: pos := m.arg16() - v, ok := m.current().(rideBoolean) + val, err := m.pop() + if err != nil { + return nil, errors.Wrap(err, "OpJumpIfFalse") + } + v, ok := val.(rideBoolean) if !ok { return nil, errors.Errorf("not a boolean value '%v' of type '%T'", m.current(), m.current()) } @@ -144,23 +150,38 @@ func (m *vm) run() (RideResult, error) { m.push(frame.args[n]) case OpReturn: l := len(m.calls) + if l == 0 { + if len(m.stack) > 0 { + v, err := m.pop() + if err != nil { + return nil, errors.Wrap(err, "failed to get result value") + } + switch tv := v.(type) { + case rideBoolean: + return ScriptResult{res: bool(tv)}, nil + default: + return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) + } + } + return nil, errors.New("no result after script execution") + } var f frame f, m.calls = m.calls[l-1], m.calls[:l-1] m.ip = f.back - case OpHalt: - if len(m.stack) > 0 { - v, err := m.pop() - if err != nil { - return nil, errors.Wrap(err, "failed to get result value") - } - switch tv := v.(type) { - case rideBoolean: - return ScriptResult{res: bool(tv)}, nil - default: - return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) - } - } - return nil, errors.New("no result after script execution") + //case OpHalt: + // if len(m.stack) > 0 { + // v, err := m.pop() + // if err != nil { + // return nil, errors.Wrap(err, "failed to get result value") + // } + // switch tv := v.(type) { + // case rideBoolean: + // return ScriptResult{res: bool(tv)}, nil + // default: + // return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) + // } + // } + // return nil, errors.New("no result after script execution") case OpGlobal: id := m.arg16() constructor := m.globals(id) diff --git a/pkg/ride/vm_test.go b/pkg/ride/vm_test.go index 8ffd6ba27a..94c3d7432a 100644 --- a/pkg/ride/vm_test.go +++ b/pkg/ride/vm_test.go @@ -19,54 +19,54 @@ import ( //go:generate moq -pkg ride -out types_moq_test.go ../types SmartState:MockSmartState func TestExecution(t *testing.T) { - state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return testTransferWithProofs(), nil - }} - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - } + //state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + // return testTransferWithProofs(), nil + //}} + //env := &MockRideEnvironment{ + // transactionFunc: testTransferObject, + // stateFunc: func() types.SmartState { + // return state + // }, + // schemeFunc: func() byte { + // return 'T' + // }, + //} for _, test := range []struct { comment string source string env RideEnvironment res bool }{ - {`V1: true`, "AQa3b8tH", nil, true}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, - {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - {`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, - {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, - {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, - {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, + //{`V1: true`, "AQa3b8tH", nil, true}, + //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, + //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, + //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, + //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, + //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, - {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, - {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - {`false`, `AQfeYll6`, nil, false}, - {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, - {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, - {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, - {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, - {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, - {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, nil, true}, - {`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==`, nil, true}, - {`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, + //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, + //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + //{`false`, `AQfeYll6`, nil, false}, + //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, + //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, + //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, + //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, nil, true}, + //{`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==`, nil, true}, + //{`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, nil, true}, } { src, err := base64.StdEncoding.DecodeString(test.source) require.NoError(t, err, test.comment) From 393bea6a3b6a212cde49984afb8bee72b73a96d4 Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 23 Oct 2020 15:22:15 +0300 Subject: [PATCH 02/55] Context for func execution. --- go.mod | 1 + go.sum | 2 ++ pkg/ride/compiler2.go | 3 +++ pkg/ride/compiler2_test.go | 32 +++++++++++++++-------------- pkg/ride/compiler_fsm.go | 9 ++++++--- pkg/ride/compiler_helpers.go | 7 +++++++ pkg/ride/executable.go | 4 ++++ pkg/ride/opcodes.go | 11 +++++----- pkg/ride/vm.go | 39 ++++++++++++++++++++++++++++++++++++ 9 files changed, 85 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index c2e5bc4660..04e4f148ed 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 + github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b github.com/fxamacker/cbor/v2 v2.2.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 diff --git a/go.sum b/go.sum index c2bdddd0ef..ac56f63238 100644 --- a/go.sum +++ b/go.sum @@ -82,6 +82,8 @@ github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942/go.mod h1:ZW github.com/ethereum/go-ethereum v1.9.15/go.mod h1:slT8bPPRhXsyNTwHQxrOnjuTZ1sDXRajW11EkJ84QJ0= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b h1:pxBLQ5mIlm4mKl2lx1IhwLhpAu2XhnDDn2a+ooAN8dU= +github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b/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= diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 05c82f6496..1c70117577 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -50,6 +50,9 @@ func ccc(f Fsm, node Node) (Fsm, error) { return fsm, err } return ccc(fsm.Return(), n.Block) + //case *PropertyNode: + // n.Object + // n.Name default: return f, errors.Errorf("unknown type %T", node) } diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 28826238fe..45b448d9e4 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - //"github.com/wavesplatform/gowaves/pkg/proto" - //"github.com/wavesplatform/gowaves/pkg/types" + "github.com/wavesplatform/gowaves/pkg/proto" + "github.com/wavesplatform/gowaves/pkg/types" ) func Test_ccc(t *testing.T) { @@ -52,18 +52,18 @@ func Test_ccc(t *testing.T) { } func Test22(t *testing.T) { - //state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - // return testTransferWithProofs(), nil - //}} - //env := &MockRideEnvironment{ - // transactionFunc: testTransferObject, - // stateFunc: func() types.SmartState { - // return state - // }, - // schemeFunc: func() byte { - // return 'T' - // }, - //} + state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return testTransferWithProofs(), nil + }} + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + } for _, test := range []struct { comment string source string @@ -78,7 +78,7 @@ func Test22(t *testing.T) { //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, - {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", nil, true}, + //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", nil, true}, //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, @@ -90,6 +90,8 @@ func Test22(t *testing.T) { //{`false`, `AQfeYll6`, nil, false}, //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, + // Global variables + {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, diff --git a/pkg/ride/compiler_fsm.go b/pkg/ride/compiler_fsm.go index 68531a23db..b2818f80ce 100644 --- a/pkg/ride/compiler_fsm.go +++ b/pkg/ride/compiler_fsm.go @@ -1,7 +1,5 @@ package ride -import "fmt" - type Fsm interface { Assigment(name string) Fsm Return() Fsm @@ -25,6 +23,8 @@ type params struct { c *constants // relation of variables and it's offset. r *references + // global variables defined not in script. + ctx Context // way to get function id. f FunctionChecker } @@ -56,7 +56,10 @@ func constant(a Fsm, params params, rideType rideType) Fsm { func reference(f Fsm, params params, name string) Fsm { pos, ok := params.r.get(name) if !ok { - panic(fmt.Sprintf("reference %s not found", name)) + index := params.c.put(rideString(name)) + params.b.fillContext(index) + //panic(fmt.Sprintf("reference %s not found", name)) + return f } params.b.jump(pos) return f diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index a6ff800586..1890e6bd2c 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -2,6 +2,8 @@ package ride import "bytes" +type constid = uint16 + type builder struct { w *bytes.Buffer startAt uint16 @@ -76,6 +78,11 @@ func (b *builder) jpmIfFalse() { b.w.WriteByte(OpJumpIfFalse) } +func (b *builder) fillContext(id constid) { + b.w.WriteByte(OpFillContext) + b.w.Write(encode(id)) +} + type constants struct { values []rideType } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 0bf3ff7ea2..0ac1a4ac9b 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -13,11 +13,15 @@ func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { return nil, err } + ctx := newContext() + ctx = ctx.add("tx", environment.transaction()) + v := vm{ code: a.ByteCode, ip: int(a.EntryPoints[""]), constants: a.Constants, functions: fSelect, + context: ctx, } return v.run() diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index 57a654eb2d..774fc2b23c 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -14,9 +14,10 @@ const ( OpJumpIfFalse //07 - Moves instruction pointer to new position if value on stack is False. One parameter: new position. OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. - OpCall //0a - Call a function declared at given address. Two parameters: position of function declaration, number of arguments. - OpGlobal //0b - Load global constant. One parameter: global constant ID. - OpLoad //0c - Evaluates an expression that declared at address. One parameter: position of declaration. - OpLoadLocal //0d - Load an argument of function call on stack. One parameter: argument number. - OpRef //0e - Put reference to expression/function on stack. One parameter: position of declaration. + OpCall //10 - Call a function declared at given address. Two parameters: position of function declaration, number of arguments. + OpGlobal //11 - Load global constant. One parameter: global constant ID. + OpLoad //12 - Evaluates an expression that declared at address. One parameter: position of declaration. + OpLoadLocal //13 - Load an argument of function call on stack. One parameter: argument number. + OpRef //14 - Put reference to expression/function on stack. One parameter: position of declaration. + OpFillContext //15 - Put reference to expression/function on stack. One parameter: position of declaration. ) diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index dbd1712ea5..195df233ca 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -2,10 +2,38 @@ package ride import ( "encoding/binary" + "fmt" + im "github.com/frozen/immutable_map" "github.com/pkg/errors" ) +type Context interface { + add(name string, rideType2 rideType) Context + get(name string) (rideType, bool) +} +type ContextImpl struct { + m *im.Map +} + +func newContext() Context { + return ContextImpl{m: im.New()} +} + +func (a ContextImpl) add(name string, value rideType) Context { + return ContextImpl{ + m: a.m.Insert([]byte(name), value), + } +} + +func (a ContextImpl) get(name string) (rideType, bool) { + v, ok := a.m.Get([]byte(name)) + if !ok { + return nil, ok + } + return v.(rideType), ok +} + type frame struct { function bool back int @@ -36,6 +64,7 @@ type vm struct { stack []rideType calls []frame functionName func(int) string + context Context } func (m *vm) run() (RideResult, error) { @@ -187,6 +216,16 @@ func (m *vm) run() (RideResult, error) { constructor := m.globals(id) v := constructor(m.env) m.push(v) + + case OpFillContext: + id := m.arg16() + str := m.constants[id].(rideString) + value, ok := m.context.get(string(str)) + if !ok { + panic(fmt.Sprintf("value %s not found in context", str)) + } + m.push(value) + default: return nil, errors.Errorf("unknown code %#x", op) } From c32e8876653065c6ffcf481818c254a1ca535b9c Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 23 Oct 2020 20:25:39 +0300 Subject: [PATCH 03/55] Function definition passed tess. --- pkg/ride/compiler2.go | 3 +- pkg/ride/compiler2_test.go | 51 +++++++++--- pkg/ride/compiler_fsm.go | 13 +-- pkg/ride/compiler_fsm_assigment.go | 12 ++- pkg/ride/compiler_fsm_call.go | 15 +++- pkg/ride/compiler_fsm_conditional.go | 4 + pkg/ride/compiler_fsm_definitions.go | 4 + pkg/ride/compiler_fsm_func_declaration.go | 83 ++++++++++++++++++++ pkg/ride/compiler_helpers.go | 15 +++- pkg/ride/executable.go | 13 ++- pkg/ride/opcodes.go | 33 ++++---- pkg/ride/vm.go | 96 ++++++++++++----------- 12 files changed, 252 insertions(+), 90 deletions(-) create mode 100644 pkg/ride/compiler_fsm_func_declaration.go diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 1c70117577..25accc35a7 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -44,8 +44,7 @@ func ccc(f Fsm, node Node) (Fsm, error) { } return f.Return(), nil case *FunctionDeclarationNode: - // TODO - fsm, err := ccc(f.Assigment(n.Name), n.Body) + fsm, err := ccc(f.FuncDeclaration(n.Name, n.Arguments), n.Body) if err != nil { return fsm, err } diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 45b448d9e4..e0cf03ba24 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -70,16 +70,16 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - //{`V1: true`, "AQa3b8tH", nil, true}, - //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, - //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, - //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, - //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, + {`V1: true`, "AQa3b8tH", nil, true}, + {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, + {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + {`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, + {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, + {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, - //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, @@ -91,7 +91,7 @@ func Test22(t *testing.T) { //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, // Global variables - {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, + //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, @@ -122,3 +122,34 @@ func Test22(t *testing.T) { assert.Equal(t, test.res, r.Result(), test.comment) } } + +/* + +let x = 1; let y = 2; func gt(i: Int, i2: Int) = i > i2; gt(x, y) + +*/ +func Test33(t *testing.T) { + + e := Executable{ + LibVersion: 3, + ByteCode: []byte{ + OpPush, 0, 0, OpReturn, + OpPush, 0, 1, OpReturn, + OpPushFromFrame, 0, 0, + OpPushFromFrame, 0, 1, + OpExternalCall, 0, 12, 0, 2, + OpReturn, + // ENTRYPOINT + OpJump, 0, 0, // jump to the beginning, first variable + OpJump, 0, 4, // jump to the second variable + OpJump, 0, 8, // вызов пользовательской функции add + OpReturn, + }, + Constants: []rideType{rideInt(1), rideInt(2)}, + EntryPoints: map[string]uint16{"": 20}, + } + + rs, err := e.Run(nil) + t.Log(rs) + t.Log(err) +} diff --git a/pkg/ride/compiler_fsm.go b/pkg/ride/compiler_fsm.go index b2818f80ce..40aeefc366 100644 --- a/pkg/ride/compiler_fsm.go +++ b/pkg/ride/compiler_fsm.go @@ -1,5 +1,7 @@ package ride +import "fmt" + type Fsm interface { Assigment(name string) Fsm Return() Fsm @@ -12,6 +14,7 @@ type Fsm interface { TrueBranch() Fsm FalseBranch() Fsm Bytes(b []byte) Fsm + FuncDeclaration(name string, args []string) Fsm } type FunctionChecker func(string) (uint16, bool) @@ -23,8 +26,6 @@ type params struct { c *constants // relation of variables and it's offset. r *references - // global variables defined not in script. - ctx Context // way to get function id. f FunctionChecker } @@ -56,10 +57,10 @@ func constant(a Fsm, params params, rideType rideType) Fsm { func reference(f Fsm, params params, name string) Fsm { pos, ok := params.r.get(name) if !ok { - index := params.c.put(rideString(name)) - params.b.fillContext(index) - //panic(fmt.Sprintf("reference %s not found", name)) - return f + //index := params.c.put(rideString(name)) + //params.b.fillContext(index) + panic(fmt.Sprintf("reference %s not found", name)) + //return f } params.b.jump(pos) return f diff --git a/pkg/ride/compiler_fsm_assigment.go b/pkg/ride/compiler_fsm_assigment.go index 0f256c5356..3e3f459b5f 100644 --- a/pkg/ride/compiler_fsm_assigment.go +++ b/pkg/ride/compiler_fsm_assigment.go @@ -8,6 +8,10 @@ type AssigmentFsm struct { offset uint16 } +func (a AssigmentFsm) FuncDeclaration(name string, args []string) Fsm { + return funcDeclarationFsmTransition(a, a.params, name, args) +} + func (a AssigmentFsm) Bytes(b []byte) Fsm { return constant(a, a.params, rideBytes(b)) } @@ -43,16 +47,18 @@ func newAssigmentFsm(prev Fsm, p params, name string) Fsm { b: p.b, c: p.c, f: p.f, - // Create new scope, so assigment in assigment can't affect global state. - r: newReferences(p.r), + r: p.r, }, name: name, offset: p.b.len(), } } +// Create new scope, so assigment in assigment can't affect global state. func (a AssigmentFsm) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) + params := a.params + params.r = newReferences(params.r) + return assigmentFsmTransition(a, params, name) } func (a AssigmentFsm) Return() Fsm { diff --git a/pkg/ride/compiler_fsm_call.go b/pkg/ride/compiler_fsm_call.go index fb512f33f8..56d9009d38 100644 --- a/pkg/ride/compiler_fsm_call.go +++ b/pkg/ride/compiler_fsm_call.go @@ -10,6 +10,10 @@ type CallFsm struct { argc uint16 } +func (a CallFsm) FuncDeclaration(name string, args []string) Fsm { + return funcDeclarationFsmTransition(a, a.params, name, args) +} + func (a CallFsm) Bytes(b []byte) Fsm { return constant(a, a.params, rideBytes(b)) } @@ -56,9 +60,16 @@ func (a CallFsm) Long(value int64) Fsm { } func (a CallFsm) Return() Fsm { - n, ok := a.f(a.name) + // check user functions + n, ok := a.r.get(a.name) + if ok { + a.b.call(n, a.argc) + return a.prev + } + + n, ok = a.f(a.name) if !ok { - panic(fmt.Sprintf("function names %s not found", a.name)) + panic(fmt.Sprintf("function named %s not found", a.name)) } a.b.externalCall(n, a.argc) return a.prev diff --git a/pkg/ride/compiler_fsm_conditional.go b/pkg/ride/compiler_fsm_conditional.go index 80efdcbb35..c8dba521ea 100644 --- a/pkg/ride/compiler_fsm_conditional.go +++ b/pkg/ride/compiler_fsm_conditional.go @@ -7,6 +7,10 @@ type ConditionalFsm struct { patchPosition uint16 } +func (a ConditionalFsm) FuncDeclaration(name string, args []string) Fsm { + panic("Illegal call FuncDeclaration on ConditionalFsm") +} + func (a ConditionalFsm) Bytes(b []byte) Fsm { return constant(a, a.params, rideBytes(b)) } diff --git a/pkg/ride/compiler_fsm_definitions.go b/pkg/ride/compiler_fsm_definitions.go index 5bb1c0fc4f..1454613867 100644 --- a/pkg/ride/compiler_fsm_definitions.go +++ b/pkg/ride/compiler_fsm_definitions.go @@ -6,6 +6,10 @@ type DefinitionFsm struct { params } +func (a DefinitionFsm) FuncDeclaration(name string, args []string) Fsm { + return funcDeclarationFsmTransition(a, a.params, name, args) +} + func (a DefinitionFsm) Bytes(b []byte) Fsm { panic("Illegal call `Bytes` on `DefinitionFsm`") } diff --git a/pkg/ride/compiler_fsm_func_declaration.go b/pkg/ride/compiler_fsm_func_declaration.go new file mode 100644 index 0000000000..82c863e7f6 --- /dev/null +++ b/pkg/ride/compiler_fsm_func_declaration.go @@ -0,0 +1,83 @@ +package ride + +type FuncDeclarationFsm struct { + params + prev Fsm + name string + args []string + offset uint16 + globalScope *references +} + +func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []string) Fsm { + // save reference to global scope, where code lower that function will be able to use it. + globalScope := params.r + // all variable we add only visible to current scope, + // avoid corrupting parent state. + params.r = newReferences(params.r) + for i := range args { + params.r.set(args[i], params.b.len()) + params.b.w.WriteByte(OpPushFromFrame) + params.b.w.Write(encode(uint16(i))) + params.b.ret() + } + + return &FuncDeclarationFsm{ + prev: prev, + name: name, + args: args, + params: params, + offset: params.b.len(), + globalScope: globalScope, + } +} + +func (a FuncDeclarationFsm) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a FuncDeclarationFsm) Return() Fsm { + a.globalScope.set(a.name, a.offset) + a.b.ret() + return a.prev +} + +func (a FuncDeclarationFsm) Long(value int64) Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a FuncDeclarationFsm) Reference(name string) Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) Boolean(v bool) Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) String(s string) Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) Condition() Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) TrueBranch() Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) FalseBranch() Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) Bytes(b []byte) Fsm { + panic("implement me") +} + +func (a FuncDeclarationFsm) FuncDeclaration(name string, args []string) Fsm { + panic("Illegal call `FuncDeclaration` is `FuncDeclarationFsm`") +} diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 1890e6bd2c..d4153240f0 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -66,6 +66,13 @@ func (b *builder) externalCall(id uint16, argc uint16) { b.w.Write(encode(argc)) } +// Call user defined function. +func (b *builder) call(id uint16, argc uint16) { + b.w.WriteByte(OpCall) + b.w.Write(encode(id)) + b.w.Write(encode(argc)) +} + func (b *builder) startPos() { b.startAt = uint16(b.w.Len()) } @@ -78,10 +85,10 @@ func (b *builder) jpmIfFalse() { b.w.WriteByte(OpJumpIfFalse) } -func (b *builder) fillContext(id constid) { - b.w.WriteByte(OpFillContext) - b.w.Write(encode(id)) -} +//func (b *builder) fillContext(id constid) { +// b.w.WriteByte(OpFillContext) +// b.w.Write(encode(id)) +//} type constants struct { values []rideType diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 0ac1a4ac9b..d57f781a9f 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -13,16 +13,23 @@ func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { return nil, err } - ctx := newContext() - ctx = ctx.add("tx", environment.transaction()) + provider, err := selectFunctionNameProvider(a.LibVersion) + if err != nil { + return nil, err + } + //ctx := newContext() + //ctx = ctx.add("tx", environment.transaction()) v := vm{ code: a.ByteCode, ip: int(a.EntryPoints[""]), constants: a.Constants, functions: fSelect, - context: ctx, + //context: ctx, + functionName: provider, } + //v.push(environment.transaction()) + return v.run() } diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index 774fc2b23c..a9d178dff3 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -4,20 +4,21 @@ package ride // Parameter is 2 bytes length const ( - OpHalt byte = iota //00 - Halts program execution. No parameters. - OpReturn //01 - Returns from declaration to stored position. No parameters. - OpPush //02 - Put constant on stack. One parameter: constant ID. - OpPop //03 - Removes value from stack. No parameters. - OpTrue //04 - Put True value on stack. No parameters. - OpFalse //05 - Put False value on stack. No parameters. - OpJump //06 - Moves instruction pointer to new position. One parameter: new position. - OpJumpIfFalse //07 - Moves instruction pointer to new position if value on stack is False. One parameter: new position. - OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. - OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. - OpCall //10 - Call a function declared at given address. Two parameters: position of function declaration, number of arguments. - OpGlobal //11 - Load global constant. One parameter: global constant ID. - OpLoad //12 - Evaluates an expression that declared at address. One parameter: position of declaration. - OpLoadLocal //13 - Load an argument of function call on stack. One parameter: argument number. - OpRef //14 - Put reference to expression/function on stack. One parameter: position of declaration. - OpFillContext //15 - Put reference to expression/function on stack. One parameter: position of declaration. + OpHalt byte = iota //00 - Halts program execution. No parameters. + OpReturn //01 - Returns from declaration to stored position. No parameters. + OpPush //02 - Put constant on stack. One parameter: constant ID. + OpPop //03 - Removes value from stack. No parameters. + OpTrue //04 - Put True value on stack. No parameters. + OpFalse //05 - Put False value on stack. No parameters. + OpJump //06 - Moves instruction pointer to new position. One parameter: new position. + OpJumpIfFalse //07 - Moves instruction pointer to new position if value on stack is False. One parameter: new position. + OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. + OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. + OpCall //10 - Call a function declared at given address. Two parameters: position of function declaration, number of arguments. + OpGlobal //11 - Load global constant. One parameter: global constant ID. + OpLoad //12 - Evaluates an expression that declared at address. One parameter: position of declaration. + OpLoadLocal //13 - Load an argument of function call on stack. One parameter: argument number. + OpRef //14 - Put reference to expression/function on stack. One parameter: position of declaration. + OpFillContext //15 - Put reference to expression/function on stack. One parameter: position of declaration. + OpPushFromFrame //16 ) diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 195df233ca..10f4bea004 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -2,47 +2,48 @@ package ride import ( "encoding/binary" - "fmt" - im "github.com/frozen/immutable_map" + //im "github.com/frozen/immutable_map" "github.com/pkg/errors" ) -type Context interface { - add(name string, rideType2 rideType) Context - get(name string) (rideType, bool) -} -type ContextImpl struct { - m *im.Map -} - -func newContext() Context { - return ContextImpl{m: im.New()} -} - -func (a ContextImpl) add(name string, value rideType) Context { - return ContextImpl{ - m: a.m.Insert([]byte(name), value), - } -} - -func (a ContextImpl) get(name string) (rideType, bool) { - v, ok := a.m.Get([]byte(name)) - if !ok { - return nil, ok - } - return v.(rideType), ok -} +//type Context interface { +// add(name string, rideType2 rideType) Context +// get(name string) (rideType, bool) +//} +//type ContextImpl struct { +// m *im.Map +//} +// +//func newContext() Context { +// return ContextImpl{m: im.New()} +//} +// +//func (a ContextImpl) add(name string, value rideType) Context { +// return ContextImpl{ +// m: a.m.Insert([]byte(name), value), +// } +//} +// +//func (a ContextImpl) get(name string) (rideType, bool) { +// v, ok := a.m.Get([]byte(name)) +// if !ok { +// return nil, ok +// } +// return v.(rideType), ok +//} type frame struct { - function bool - back int - args []rideType + function bool + back int + args []rideType + stackSize int } -func newExpressionFrame(pos int) frame { +func newExpressionFrame(pos int, stackSize int) frame { return frame{ - back: pos, + back: pos, + stackSize: stackSize, } } @@ -64,7 +65,6 @@ type vm struct { stack []rideType calls []frame functionName func(int) string - context Context } func (m *vm) run() (RideResult, error) { @@ -94,7 +94,7 @@ func (m *vm) run() (RideResult, error) { pos := m.arg16() current := m.ip m.ip = pos - m.calls = append(m.calls, newExpressionFrame(current)) + m.calls = append(m.calls, newExpressionFrame(current, len(m.stack))) case OpJumpIfFalse: pos := m.arg16() val, err := m.pop() @@ -160,7 +160,7 @@ func (m *vm) run() (RideResult, error) { m.push(res) case OpLoad: // Evaluate expression behind a LET declaration pos := m.arg16() - frame := newExpressionFrame(m.ip) // Creating new function frame with return position + frame := newExpressionFrame(m.ip, len(m.stack)) // Creating new function frame with return position m.calls = append(m.calls, frame) m.ip = pos // Continue to expression case OpLoadLocal: @@ -217,14 +217,21 @@ func (m *vm) run() (RideResult, error) { v := constructor(m.env) m.push(v) - case OpFillContext: - id := m.arg16() - str := m.constants[id].(rideString) - value, ok := m.context.get(string(str)) - if !ok { - panic(fmt.Sprintf("value %s not found in context", str)) - } - m.push(value) + //case OpFillContext: + // id := m.arg16() + // str := m.constants[id].(rideString) + // value, ok := m.context.get(string(str)) + // if !ok { + // panic(fmt.Sprintf("value %s not found in context", str)) + // } + // m.push(value) + case OpPushFromFrame: + // TODO very tricky + // The only way to achieve `OpPushFromFrame` is to OpJump, but it modifies m.calls, + // so we need to refer len(m.calls)-2. + + last := m.calls[len(m.calls)-2] + m.push(last.args[m.arg16()]) default: return nil, errors.Errorf("unknown code %#x", op) @@ -233,8 +240,9 @@ func (m *vm) run() (RideResult, error) { return nil, errors.New("broken code") } -func (m *vm) push(v rideType) { +func (m *vm) push(v rideType) constid { m.stack = append(m.stack, v) + return uint16(len(m.stack) - 1) } func (m *vm) pop() (rideType, error) { From 1975cd846f0853c645643a4763c8c4233f6c7edb Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 23 Oct 2020 20:30:31 +0300 Subject: [PATCH 04/55] Uncomment completed tests. --- pkg/ride/compiler2_test.go | 20 ++++++++++---------- pkg/ride/compiler_fsm_func_declaration.go | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index e0cf03ba24..dc1025cf2e 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -77,18 +77,18 @@ func Test22(t *testing.T) { {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, - //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, + {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, - //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, - //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - //{`false`, `AQfeYll6`, nil, false}, - //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, + {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, + {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + {`false`, `AQfeYll6`, nil, false}, + {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, // Global variables //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, diff --git a/pkg/ride/compiler_fsm_func_declaration.go b/pkg/ride/compiler_fsm_func_declaration.go index 82c863e7f6..1b306d928e 100644 --- a/pkg/ride/compiler_fsm_func_declaration.go +++ b/pkg/ride/compiler_fsm_func_declaration.go @@ -51,7 +51,7 @@ func (a FuncDeclarationFsm) Call(name string, argc uint16) Fsm { } func (a FuncDeclarationFsm) Reference(name string) Fsm { - panic("implement me") + return reference(a, a.params, name) } func (a FuncDeclarationFsm) Boolean(v bool) Fsm { @@ -63,7 +63,7 @@ func (a FuncDeclarationFsm) String(s string) Fsm { } func (a FuncDeclarationFsm) Condition() Fsm { - panic("implement me") + return conditionalTransition(a, a.params) } func (a FuncDeclarationFsm) TrueBranch() Fsm { From fb774190e80e64f89de854504662bf7bf502bac5 Mon Sep 17 00:00:00 2001 From: Frozen Date: Sat, 31 Oct 2020 01:11:42 +0300 Subject: [PATCH 05/55] Pass args as reference. --- pkg/ride/compiler2.go | 3 +- pkg/ride/compiler2_test.go | 237 ++++++++++++++++++---- pkg/ride/compiler_fsm.go | 1 + pkg/ride/compiler_fsm_call.go | 84 -------- pkg/ride/compiler_fsm_call_system.go | 104 ++++++++++ pkg/ride/compiler_fsm_call_user.go | 111 ++++++++++ pkg/ride/compiler_fsm_func_declaration.go | 26 ++- pkg/ride/compiler_helpers.go | 9 +- pkg/ride/opcodes.go | 18 +- pkg/ride/program.go | 32 +-- pkg/ride/vm.go | 181 ++++++++++------- 11 files changed, 580 insertions(+), 226 deletions(-) delete mode 100644 pkg/ride/compiler_fsm_call.go create mode 100644 pkg/ride/compiler_fsm_call_system.go create mode 100644 pkg/ride/compiler_fsm_call_user.go diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 25accc35a7..7001b29bdc 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -13,9 +13,10 @@ func ccc(f Fsm, node Node) (Fsm, error) { case *LongNode: return f.Long(n.Value), nil case *FunctionCallNode: + var err error f = f.Call(n.Name, uint16(len(n.Arguments))) for i := range n.Arguments { - f, err := ccc(f, n.Arguments[i]) + f, err = ccc(f, n.Arguments[i]) if err != nil { return f, err } diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index dc1025cf2e..010e4cfccc 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -1,6 +1,7 @@ package ride import ( + "bytes" "encoding/base64" "testing" @@ -46,9 +47,7 @@ func Test_ccc(t *testing.T) { sr, err := v.run() require.NoError(t, err) - - t.Log(sr) - + require.True(t, sr.Result()) } func Test22(t *testing.T) { @@ -70,25 +69,28 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - {`V1: true`, "AQa3b8tH", nil, true}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, - {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - {`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, - {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, - {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, - {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, - {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, - {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, - {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - {`false`, `AQfeYll6`, nil, false}, - {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, + //{`V1: true`, "AQa3b8tH", nil, true}, + //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, + //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, + //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, + //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, + //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, + //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, + //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + //{`false`, `AQfeYll6`, nil, false}, + //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, // Global variables //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, @@ -130,26 +132,185 @@ let x = 1; let y = 2; func gt(i: Int, i2: Int) = i > i2; gt(x, y) */ func Test33(t *testing.T) { + code, entryPoint := buildCode( + at(1), OpPush, 0, 0, OpReturn, + at(2), OpPush, 0, 1, OpReturn, + // + at(3), + OpGotoArg, 0, 0, + OpGotoArg, 0, 1, + OpExternalCall, 0, 12, 0, 2, + OpReturn, + // ENTRYPOINT + at(0), + OpPushArg, to(1), // jump to the beginning, first variable + OpPushArg, to(2), // jump to the second variable + OpCall, 0, 8, // вызов пользовательской функции add + OpReturn, + ) + e := Executable{ - LibVersion: 3, - ByteCode: []byte{ - OpPush, 0, 0, OpReturn, - OpPush, 0, 1, OpReturn, - OpPushFromFrame, 0, 0, - OpPushFromFrame, 0, 1, - OpExternalCall, 0, 12, 0, 2, - OpReturn, - // ENTRYPOINT - OpJump, 0, 0, // jump to the beginning, first variable - OpJump, 0, 4, // jump to the second variable - OpJump, 0, 8, // вызов пользовательской функции add - OpReturn, - }, - Constants: []rideType{rideInt(1), rideInt(2)}, - EntryPoints: map[string]uint16{"": 20}, + LibVersion: 3, + ByteCode: code, + Constants: []rideType{rideInt(2), rideInt(1)}, + EntryPoints: map[string]uint16{"": entryPoint}, } rs, err := e.Run(nil) t.Log(rs) t.Log(err) } + +func buildCode(i ...interface{}) ([]byte, uint16) { + marks := make(map[int]uint16) + b := new(bytes.Buffer) + for _, inf := range i { + switch n := inf.(type) { + case byte: + b.WriteByte(n) + case int: + b.WriteByte(byte(n)) + case mark: + marks[n.id] = uint16(b.Len()) + case toMark: + b.Write(encode(marks[n.id])) + } + } + return b.Bytes(), marks[0] +} + +type mark struct { + id int +} + +func at(id int) mark { + return mark{ + id: id, + } +} + +type toMark struct { + id int +} + +func to(id int) toMark { + return toMark{id} +} + +func TestBuildCode(t *testing.T) { + rs, entryPoint := buildCode(1, at(2), 2, at(0), to(2)) + require.Equal(t, []byte{1, 2, 0, 1}, rs) + require.Equal(t, uint16(2), entryPoint) +} + +// 1 == 1 +func TestCallExternal(t *testing.T) { + n := &FunctionCallNode{ + Name: "0", + Arguments: []Node{ + &LongNode{ + Value: 1, + }, + &LongNode{ + Value: 1, + }, + }, + } + + f, err := compileSimpleScript(3, n) + require.NoError(t, err) + + require.Equal(t, + []byte{ + OpPush, 0, 0, + OpPush, 0, 1, + OpExternalCall, 0, 3, 0, 2, + OpReturn, + }, + f.ByteCode) +} + +//func a() = 1; a() == 1 +func TestDoubleCall(t *testing.T) { + n := &FunctionDeclarationNode{ + Name: "a", + Arguments: nil, + Body: &LongNode{ + Value: 1, + }, + Block: &FunctionCallNode{ + Name: "0", + Arguments: []Node{ + &FunctionCallNode{ + Name: "a", + Arguments: nil, + }, + &LongNode{ + Value: 1, + }, + }, + }, + } + + f, err := compileSimpleScript(3, n) + require.NoError(t, err) + + require.Equal(t, + []byte{ + OpPush, 0, 0, + OpPopCtx, + OpReturn, + + OpCall, 0, 0, + OpPush, 0, 1, + OpExternalCall, 0, 3, 0, 2, + OpReturn, + }, + f.ByteCode) + + require.EqualValues(t, 5, f.EntryPoints[""]) + + rs, err := f.Run(nil) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) +} + +// func id(v: Boolean) = v; id(true) +func TestCallWithConstArg(t *testing.T) { + n := &FunctionDeclarationNode{ + Name: "id", + Arguments: []string{"v"}, + Body: &ReferenceNode{Name: "v"}, + Block: &FunctionCallNode{ + Name: "id", + Arguments: []Node{ + &BooleanNode{ + Value: true, + }, + }, + }, + invocationParameter: "", + } + + f, err := compileSimpleScript(3, n) + require.NoError(t, err) + + require.Equal(t, + []byte{ + OpGotoArg, 0, 0, OpReturn, // arguments section + OpJump, 0, 0, // Function execution code. One line: reference to `v` argument. + OpPopCtx, + OpReturn, + + OpTrue, OpReturn, + OpPushArg, 0, 9, + OpCall, 0, 4, + + OpReturn, + }, + f.ByteCode) + + rs, err := f.Run(nil) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) +} diff --git a/pkg/ride/compiler_fsm.go b/pkg/ride/compiler_fsm.go index 40aeefc366..5b27fe5043 100644 --- a/pkg/ride/compiler_fsm.go +++ b/pkg/ride/compiler_fsm.go @@ -33,6 +33,7 @@ type params struct { func long(f Fsm, params params, value int64) Fsm { index := params.c.put(rideInt(value)) params.b.push(index) + params.b.ret() return f } diff --git a/pkg/ride/compiler_fsm_call.go b/pkg/ride/compiler_fsm_call.go deleted file mode 100644 index 56d9009d38..0000000000 --- a/pkg/ride/compiler_fsm_call.go +++ /dev/null @@ -1,84 +0,0 @@ -package ride - -import "fmt" - -// Function call -type CallFsm struct { - prev Fsm - params - name string - argc uint16 -} - -func (a CallFsm) FuncDeclaration(name string, args []string) Fsm { - return funcDeclarationFsmTransition(a, a.params, name, args) -} - -func (a CallFsm) Bytes(b []byte) Fsm { - return constant(a, a.params, rideBytes(b)) -} - -func (a CallFsm) Condition() Fsm { - return conditionalTransition(a, a.params) -} - -func (a CallFsm) TrueBranch() Fsm { - panic("Illegal call `TrueBranch` on CallFsm") -} - -func (a CallFsm) FalseBranch() Fsm { - panic("Illegal call `FalseBranch` on CallFsm") -} - -func (a CallFsm) String(s string) Fsm { - return str(a, a.params, s) -} - -func (a CallFsm) Boolean(v bool) Fsm { - return boolean(a, a.params, v) -} - -func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { - return newCallFsm(prev, params, name, argc) -} - -func newCallFsm(prev Fsm, params params, name string, argc uint16) Fsm { - return &CallFsm{ - prev: prev, - params: params, - name: name, - argc: argc, - } -} - -func (a CallFsm) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) -} - -func (a CallFsm) Long(value int64) Fsm { - return long(a, a.params, value) -} - -func (a CallFsm) Return() Fsm { - // check user functions - n, ok := a.r.get(a.name) - if ok { - a.b.call(n, a.argc) - return a.prev - } - - n, ok = a.f(a.name) - if !ok { - panic(fmt.Sprintf("function named %s not found", a.name)) - } - a.b.externalCall(n, a.argc) - return a.prev -} - -func (a CallFsm) Call(name string, argc uint16) Fsm { - return callTransition(a, a.params, name, argc) -} - -func (a CallFsm) Reference(name string) Fsm { - return reference(a, a.params, name) -} diff --git a/pkg/ride/compiler_fsm_call_system.go b/pkg/ride/compiler_fsm_call_system.go new file mode 100644 index 0000000000..e3cee316c2 --- /dev/null +++ b/pkg/ride/compiler_fsm_call_system.go @@ -0,0 +1,104 @@ +package ride + +import "fmt" + +// Function call +type CallSystemFsm struct { + prev Fsm + params + name string + argc uint16 + // positions of arguments + argn []uint16 +} + +func (a CallSystemFsm) FuncDeclaration(name string, args []string) Fsm { + return funcDeclarationFsmTransition(a, a.params, name, args) +} + +func (a CallSystemFsm) Bytes(b []byte) Fsm { + return constant(a, a.params, rideBytes(b)) +} + +func (a CallSystemFsm) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a CallSystemFsm) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on CallFsm") +} + +func (a CallSystemFsm) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on CallFsm") +} + +func (a CallSystemFsm) String(s string) Fsm { + return str(a, a.params, s) +} + +func (a CallSystemFsm) Boolean(v bool) Fsm { + return boolean(a, a.params, v) +} + +func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { + if _, ok := params.r.get(name); ok { + return newCallUserFsm(prev, params, name, argc) + } + return newCallSystemFsm(prev, params, name, argc) +} + +func newCallSystemFsm(prev Fsm, params params, name string, argc uint16) Fsm { + return &CallSystemFsm{ + prev: prev, + params: params, + name: name, + argc: argc, + } +} + +func (a CallSystemFsm) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a CallSystemFsm) Long(value int64) Fsm { + index := a.params.c.put(rideInt(value)) + a.params.b.push(index) + return a +} + +func (a CallSystemFsm) Return() Fsm { + + //// check user functions + //n, ok := a.r.get(a.name) + //if ok { + // a.b.startPos() + // for _, pos := range a.argn { + // a.b.writeByte(OpPushArg) + // a.b.write(encode(pos)) + // //a.b.writeByte(OpReturn) + // } + // + // a.b.call(n, a.argc) + // return a.prev + //} + + //a.b.startPos() + n, ok := a.f(a.name) + if !ok { + panic(fmt.Sprintf("system function named `%s` not found", a.name)) + } + //for _, pos := range a.argn { + // a.b.writeByte(OpJump) + // a.b.write(encode(pos)) + //} + a.b.externalCall(n, a.argc) + return a.prev +} + +func (a CallSystemFsm) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a CallSystemFsm) Reference(name string) Fsm { + return reference(a, a.params, name) +} diff --git a/pkg/ride/compiler_fsm_call_user.go b/pkg/ride/compiler_fsm_call_user.go new file mode 100644 index 0000000000..40c4bf2b8f --- /dev/null +++ b/pkg/ride/compiler_fsm_call_user.go @@ -0,0 +1,111 @@ +package ride + +import "fmt" + +// Function call +type CallUserFsm struct { + prev Fsm + params + name string + argc uint16 + // positions of arguments + argn []uint16 +} + +func (a CallUserFsm) FuncDeclaration(name string, args []string) Fsm { + return funcDeclarationFsmTransition(a, a.params, name, args) +} + +func (a CallUserFsm) Bytes(b []byte) Fsm { + return constant(a, a.params, rideBytes(b)) +} + +func (a CallUserFsm) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a CallUserFsm) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on CallFsm") +} + +func (a CallUserFsm) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on CallFsm") +} + +func (a CallUserFsm) String(s string) Fsm { + return str(a, a.params, s) +} + +func (a CallUserFsm) Boolean(v bool) Fsm { + pos := a.b.len() + a.b.writeByte(OpTrue) + a.argn = append(a.argn, pos) + a.b.ret() + return a +} + +//func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { +// return newCallFsm(prev, params, name, argc) +//} + +func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { + return &CallUserFsm{ + prev: prev, + params: params, + name: name, + argc: argc, + } +} + +func (a CallUserFsm) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a CallUserFsm) Long(value int64) Fsm { + pos := a.b.len() + index := a.params.c.put(rideInt(value)) + a.params.b.push(index) + a.argn = append(a.argn, pos) + a.b.ret() + return a +} + +func (a CallUserFsm) Return() Fsm { + + // check user functions + n, ok := a.r.get(a.name) + if !ok { + panic(fmt.Sprintf("user function `%s` not found", a.name)) + } + //if ok { + a.b.startPos() + for _, pos := range a.argn { + a.b.writeByte(OpPushArg) + a.b.write(encode(pos)) + //a.b.writeByte(OpReturn) + } + + a.b.call(n, a.argc) + return a.prev + //} + + //a.b.startPos() + //n, ok = a.f(a.name) + //if !ok { + // panic(fmt.Sprintf("function named %s not found", a.name)) + //} + //for _, pos := range a.argn { + // a.b.writeByte(OpJump) + // a.b.write(encode(pos)) + //} + //a.b.externalCall(n, a.argc) + //return a.prev +} + +func (a CallUserFsm) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a CallUserFsm) Reference(name string) Fsm { + return reference(a, a.params, name) +} diff --git a/pkg/ride/compiler_fsm_func_declaration.go b/pkg/ride/compiler_fsm_func_declaration.go index 1b306d928e..77a13c3460 100644 --- a/pkg/ride/compiler_fsm_func_declaration.go +++ b/pkg/ride/compiler_fsm_func_declaration.go @@ -1,10 +1,21 @@ package ride +type arguments []string + +func (a arguments) pos(name string) int { + for i := range a { + if a[i] == name { + return i + } + } + return -1 +} + type FuncDeclarationFsm struct { params prev Fsm name string - args []string + args arguments offset uint16 globalScope *references } @@ -12,14 +23,14 @@ type FuncDeclarationFsm struct { func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []string) Fsm { // save reference to global scope, where code lower that function will be able to use it. globalScope := params.r - // all variable we add only visible to current scope, - // avoid corrupting parent state. + //// all variable we add only visible to current scope, + //// avoid corrupting parent state. params.r = newReferences(params.r) for i := range args { params.r.set(args[i], params.b.len()) - params.b.w.WriteByte(OpPushFromFrame) + params.b.w.WriteByte(OpGotoArg) params.b.w.Write(encode(uint16(i))) - params.b.ret() + params.b.w.WriteByte(OpReturn) } return &FuncDeclarationFsm{ @@ -38,12 +49,15 @@ func (a FuncDeclarationFsm) Assigment(name string) Fsm { func (a FuncDeclarationFsm) Return() Fsm { a.globalScope.set(a.name, a.offset) + a.b.writeByte(OpPopCtx) a.b.ret() return a.prev } func (a FuncDeclarationFsm) Long(value int64) Fsm { - panic("implement me") + index := a.params.c.put(rideInt(value)) + a.params.b.push(index) + return a } func (a FuncDeclarationFsm) Call(name string, argc uint16) Fsm { diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index d4153240f0..00e6e0416b 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -70,7 +70,6 @@ func (b *builder) externalCall(id uint16, argc uint16) { func (b *builder) call(id uint16, argc uint16) { b.w.WriteByte(OpCall) b.w.Write(encode(id)) - b.w.Write(encode(argc)) } func (b *builder) startPos() { @@ -85,6 +84,14 @@ func (b *builder) jpmIfFalse() { b.w.WriteByte(OpJumpIfFalse) } +func (b *builder) writeByte(p byte) { + b.w.WriteByte(p) +} + +func (b *builder) write(i []byte) { + b.w.Write(i) +} + //func (b *builder) fillContext(id constid) { // b.w.WriteByte(OpFillContext) // b.w.Write(encode(id)) diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index a9d178dff3..24e150d71a 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -14,11 +14,15 @@ const ( OpJumpIfFalse //07 - Moves instruction pointer to new position if value on stack is False. One parameter: new position. OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. - OpCall //10 - Call a function declared at given address. Two parameters: position of function declaration, number of arguments. - OpGlobal //11 - Load global constant. One parameter: global constant ID. - OpLoad //12 - Evaluates an expression that declared at address. One parameter: position of declaration. - OpLoadLocal //13 - Load an argument of function call on stack. One parameter: argument number. - OpRef //14 - Put reference to expression/function on stack. One parameter: position of declaration. - OpFillContext //15 - Put reference to expression/function on stack. One parameter: position of declaration. - OpPushFromFrame //16 + OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. + OpGlobal //11 0xb - Load global constant. One parameter: global constant ID. + OpLoad //12 0xc - Evaluates an expression that declared at address. One parameter: position of declaration. + OpLoadLocal //13 0xd - Load an argument of function call on stack. One parameter: argument number. + OpRef //14 0xe - Put reference to expression/function on stack. One parameter: position of declaration. + OpFillContext //15 0xf - Put reference to expression/function on stack. One parameter: position of declaration. + OpPushFromFrame //16 0x10 + OpPushArg //17 0x11 - Push value to frame: one param. + OpGotoArg //18 0x12 - Go to value stored in argument N: one param. + OpPushCtx //19 0x13 + OpPopCtx //20 0x14 ) diff --git a/pkg/ride/program.go b/pkg/ride/program.go index e384d7b9b8..6edb89ef9e 100644 --- a/pkg/ride/program.go +++ b/pkg/ride/program.go @@ -33,14 +33,14 @@ func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { return nil, errors.Wrap(err, "simple script execution failed") } m := vm{ - env: env, - code: s.Code, - ip: 0, - constants: s.Constants, - functions: fs, - globals: gcs, - stack: make([]rideType, 0, 2), - calls: make([]frame, 0, 2), + env: env, + code: s.Code, + ip: 0, + constants: s.Constants, + functions: fs, + globals: gcs, + stack: make([]rideType, 0, 2), + //calls: make([]frame, 0, 2), functionName: np, } r, err := m.run() @@ -78,14 +78,14 @@ func (s *DAppScript) Run(env RideEnvironment) (RideResult, error) { return nil, errors.Wrap(err, "script execution failed") } m := vm{ - env: env, - code: s.Code, - ip: 0, - constants: s.Constants, - functions: fs, - globals: gcs, - stack: make([]rideType, 0, 2), - calls: make([]frame, 0, 2), + env: env, + code: s.Code, + ip: 0, + constants: s.Constants, + functions: fs, + globals: gcs, + stack: make([]rideType, 0, 2), + //calls: make([]frame, 0, 2), functionName: np, } r, err := m.run() diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 10f4bea004..2689603cb9 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -34,46 +34,59 @@ import ( //} type frame struct { - function bool - back int - args []rideType - stackSize int + function bool + back int + context []int + future []int } -func newExpressionFrame(pos int, stackSize int) frame { +func newExpressionFrame(pos int) frame { return frame{ - back: pos, - stackSize: stackSize, + back: pos, } } -func newFunctionFrame(pos int, args []rideType) frame { +func newFrameContext(pos int, context args, future args) frame { return frame{ - function: true, - back: pos, - args: args, + back: pos, + context: context, + future: future, } } +//func newFunctionFrame(pos int, args []int) frame { +// return frame{ +// function: true, +// back: pos, +// args: args, +// } +//} + +type args = []int + type vm struct { - env RideEnvironment - code []byte - ip int - constants []rideType - functions func(int) rideFunction - globals func(int) rideConstructor - stack []rideType - calls []frame + env RideEnvironment + code []byte + ip int + constants []rideType + functions func(int) rideFunction + globals func(int) rideConstructor + stack []rideType + //calls []frame functionName func(int) string + context []args + jpms []int } func (m *vm) run() (RideResult, error) { if m.stack != nil { m.stack = m.stack[0:0] } - if m.calls != nil { - m.calls = m.calls[0:0] - } + // set context, current and future + m.context = append(m.context, args{}, args{}) + //if m.calls != nil { + // m.calls = m.calls[0:0] + //} //m.ip = 0 for m.ip < len(m.code) { op := m.code[m.ip] @@ -92,9 +105,10 @@ func (m *vm) run() (RideResult, error) { m.push(rideBoolean(false)) case OpJump: pos := m.arg16() - current := m.ip + //current := m.ip + m.jpms = append(m.jpms, m.ip) m.ip = pos - m.calls = append(m.calls, newExpressionFrame(current, len(m.stack))) + //m.calls = append(m.calls, newExpressionFrame(current)) case OpJumpIfFalse: pos := m.arg16() val, err := m.pop() @@ -125,18 +139,23 @@ func (m *vm) run() (RideResult, error) { m.push(v) case OpCall: pos := m.arg16() - cnt := m.arg16() - in := make([]rideType, cnt) - for i := cnt - 1; i >= 0; i-- { - v, err := m.pop() - if err != nil { - return nil, errors.Wrapf(err, "failed to call function at position %d", pos) - } - in[i] = v - } - frame := newFunctionFrame(m.ip, in) // Creating new function frame with return position - m.calls = append(m.calls, frame) - m.ip = pos // Continue to function + //cnt := m.arg16() + //in := make([]rideType, cnt) + //for i := cnt - 1; i >= 0; i-- { + // v, err := m.pop() + // if err != nil { + // return nil, errors.Wrapf(err, "failed to call function at position %d", pos) + // } + // in[i] = v + //} + //argid := m.arg16() + //m.calls = append(m.calls, newFrameContext(m.ip, m.context, m.args)) + m.jpms = append(m.jpms, m.ip) + m.ip = pos + m.context = append(m.context, args{}) + //m.context = m.args + //m.args = nil + case OpExternalCall: // Before calling external function all parameters must be evaluated and placed on stack id := m.arg16() @@ -158,27 +177,27 @@ func (m *vm) run() (RideResult, error) { return nil, err } m.push(res) - case OpLoad: // Evaluate expression behind a LET declaration - pos := m.arg16() - frame := newExpressionFrame(m.ip, len(m.stack)) // Creating new function frame with return position - m.calls = append(m.calls, frame) - m.ip = pos // Continue to expression - case OpLoadLocal: - n := m.arg16() - for i := len(m.calls) - 1; i >= 0; i-- { - - } - l := len(m.calls) - if l == 0 { - return nil, errors.New("failed to load argument on stack") - } - frame := m.calls[l-1] - if l := len(frame.args); l < n+1 { - return nil, errors.New("invalid arguments count") - } - m.push(frame.args[n]) + //case OpLoad: // Evaluate expression behind a LET declaration + // pos := m.arg16() + // frame := newExpressionFrame(m.ip) // Creating new function frame with return position + // m.calls = append(m.calls, frame) + // m.ip = pos // Continue to expression + //case OpLoadLocal: + // n := m.arg16() + // for i := len(m.calls) - 1; i >= 0; i-- { + // + // } + // l := len(m.calls) + // if l == 0 { + // return nil, errors.New("failed to load argument on stack") + // } + // frame := m.calls[l-1] + // if l := len(frame.args); l < n+1 { + // return nil, errors.New("invalid arguments count") + // } + // m.push(frame.args[n]) case OpReturn: - l := len(m.calls) + l := len(m.jpms) if l == 0 { if len(m.stack) > 0 { v, err := m.pop() @@ -194,9 +213,11 @@ func (m *vm) run() (RideResult, error) { } return nil, errors.New("no result after script execution") } - var f frame - f, m.calls = m.calls[l-1], m.calls[:l-1] - m.ip = f.back + //var f frame + m.ip, m.jpms = m.jpms[l-1], m.jpms[:l-1] + //m.ip = m.jpms[l-1] + //m.context = f.context + //m.args = f.future //case OpHalt: // if len(m.stack) > 0 { // v, err := m.pop() @@ -217,21 +238,25 @@ func (m *vm) run() (RideResult, error) { v := constructor(m.env) m.push(v) - //case OpFillContext: - // id := m.arg16() - // str := m.constants[id].(rideString) - // value, ok := m.context.get(string(str)) - // if !ok { - // panic(fmt.Sprintf("value %s not found in context", str)) - // } - // m.push(value) - case OpPushFromFrame: - // TODO very tricky - // The only way to achieve `OpPushFromFrame` is to OpJump, but it modifies m.calls, - // so we need to refer len(m.calls)-2. + case OpPushArg: + arg := m.arg16() + last := len(m.context) - 1 + m.context[last] = append(m.context[last], arg) + + case OpGotoArg: + argid := m.arg16() + current := len(m.context) - 2 + m.jpms = append(m.jpms, m.ip) + //m.calls = append(m.calls, newFrameContext(m.ip, m.context, m.args)) + m.ip = m.context[current][argid] + //m.context = m.args + //m.args = nil - last := m.calls[len(m.calls)-2] - m.push(last.args[m.arg16()]) + case OpPushCtx: + m.context = append(m.context, args{}) + case OpPopCtx: + m.context = m.context[:len(m.context)-2] + m.context = append(m.context, args{}) default: return nil, errors.Errorf("unknown code %#x", op) @@ -240,6 +265,16 @@ func (m *vm) run() (RideResult, error) { return nil, errors.New("broken code") } +//func (m *vm) goTo(pos int) { +// f := m.nextFrame +// f.back = pos +// +// m.calls = append(m.calls, f) +// m.ip = pos // Continue to function +// m.args = m.curFrame +// m.curFrame = m.nextFrame +//} + func (m *vm) push(v rideType) constid { m.stack = append(m.stack, v) return uint16(len(m.stack) - 1) From d20052b0605cb0fe2823d628a991d36693ed3384 Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 3 Nov 2020 16:16:17 +0300 Subject: [PATCH 06/55] Pass args as mem storage. --- pkg/ride/compiler2.go | 3 ++- pkg/ride/compiler2_test.go | 14 +++++++------- pkg/ride/compiler_fsm.go | 15 +++++++++++++++ pkg/ride/compiler_fsm_call_user.go | 7 ++++++- pkg/ride/compiler_fsm_conditional.go | 1 + pkg/ride/compiler_fsm_definitions.go | 4 +++- pkg/ride/compiler_fsm_func_declaration.go | 8 ++++++-- pkg/ride/opcodes.go | 2 +- pkg/ride/vm.go | 16 ++++++++++------ 9 files changed, 51 insertions(+), 19 deletions(-) diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 7001b29bdc..c812ce4303 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -70,8 +70,9 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { b := newBuilder() c := newConstants() r := newReferences(nil) + u := &uniqid{} - f := NewDefinitionsFsm(b, c, r, fCheck) + f := NewDefinitionsFsm(b, c, r, u, fCheck) f, err = ccc(f, node) if err != nil { return nil, err diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 010e4cfccc..30d6cc58e7 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -78,7 +78,7 @@ func Test22(t *testing.T) { //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, @@ -91,9 +91,9 @@ func Test22(t *testing.T) { //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, //{`false`, `AQfeYll6`, nil, false}, //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, - //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, + //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, // Global variables - //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, + {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, @@ -137,8 +137,8 @@ func Test33(t *testing.T) { at(2), OpPush, 0, 1, OpReturn, // at(3), - OpGotoArg, 0, 0, - OpGotoArg, 0, 1, + OpUseArg, 0, 0, + OpUseArg, 0, 1, OpExternalCall, 0, 12, 0, 2, OpReturn, // ENTRYPOINT @@ -297,13 +297,13 @@ func TestCallWithConstArg(t *testing.T) { require.Equal(t, []byte{ - OpGotoArg, 0, 0, OpReturn, // arguments section + OpUseArg, 0, 1, OpReturn, // arguments section OpJump, 0, 0, // Function execution code. One line: reference to `v` argument. OpPopCtx, OpReturn, OpTrue, OpReturn, - OpPushArg, 0, 9, + OpPushArg, 0, 1, 0, 9, OpCall, 0, 4, OpReturn, diff --git a/pkg/ride/compiler_fsm.go b/pkg/ride/compiler_fsm.go index 5b27fe5043..53f805eeb0 100644 --- a/pkg/ride/compiler_fsm.go +++ b/pkg/ride/compiler_fsm.go @@ -17,6 +17,19 @@ type Fsm interface { FuncDeclaration(name string, args []string) Fsm } +type uniqid struct { + id uint16 +} + +func (a *uniqid) next() uint16 { + a.id++ + return a.id +} + +func (a uniqid) cur() uint16 { + return a.id +} + type FunctionChecker func(string) (uint16, bool) type params struct { @@ -28,6 +41,8 @@ type params struct { r *references // way to get function id. f FunctionChecker + // unique id for func params + u *uniqid } func long(f Fsm, params params, value int64) Fsm { diff --git a/pkg/ride/compiler_fsm_call_user.go b/pkg/ride/compiler_fsm_call_user.go index 40c4bf2b8f..ba10cd1580 100644 --- a/pkg/ride/compiler_fsm_call_user.go +++ b/pkg/ride/compiler_fsm_call_user.go @@ -79,8 +79,13 @@ func (a CallUserFsm) Return() Fsm { } //if ok { a.b.startPos() - for _, pos := range a.argn { + for i, pos := range a.argn { a.b.writeByte(OpPushArg) + uniqid, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i)) + if !ok { + panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) + } + a.b.write(encode(uniqid)) a.b.write(encode(pos)) //a.b.writeByte(OpReturn) } diff --git a/pkg/ride/compiler_fsm_conditional.go b/pkg/ride/compiler_fsm_conditional.go index c8dba521ea..af766e05e9 100644 --- a/pkg/ride/compiler_fsm_conditional.go +++ b/pkg/ride/compiler_fsm_conditional.go @@ -33,6 +33,7 @@ func (a ConditionalFsm) TrueBranch() Fsm { } func (a ConditionalFsm) FalseBranch() Fsm { + a.b.ret() a.b.patch(a.patchPosition, encode(a.b.len())) return a } diff --git a/pkg/ride/compiler_fsm_definitions.go b/pkg/ride/compiler_fsm_definitions.go index 1454613867..2a894c4290 100644 --- a/pkg/ride/compiler_fsm_definitions.go +++ b/pkg/ride/compiler_fsm_definitions.go @@ -15,6 +15,7 @@ func (a DefinitionFsm) Bytes(b []byte) Fsm { } func (a DefinitionFsm) Condition() Fsm { + a.b.startPos() return conditionalTransition(a, a.params) } @@ -34,13 +35,14 @@ type BuildExecutable interface { BuildExecutable(version int) *Executable } -func NewDefinitionsFsm(b *builder, c *constants, r *references, f FunctionChecker) Fsm { +func NewDefinitionsFsm(b *builder, c *constants, r *references, u *uniqid, f FunctionChecker) Fsm { return &DefinitionFsm{ params: params{ b: b, c: c, r: r, f: f, + u: u, }, } } diff --git a/pkg/ride/compiler_fsm_func_declaration.go b/pkg/ride/compiler_fsm_func_declaration.go index 77a13c3460..09dfe6a156 100644 --- a/pkg/ride/compiler_fsm_func_declaration.go +++ b/pkg/ride/compiler_fsm_func_declaration.go @@ -1,5 +1,7 @@ package ride +import "fmt" + type arguments []string func (a arguments) pos(name string) int { @@ -28,8 +30,10 @@ func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []s params.r = newReferences(params.r) for i := range args { params.r.set(args[i], params.b.len()) - params.b.w.WriteByte(OpGotoArg) - params.b.w.Write(encode(uint16(i))) + // set to global + globalScope.set(fmt.Sprintf("%s$%d", name, i), params.u.next()) + params.b.w.WriteByte(OpUseArg) + params.b.w.Write(encode(params.u.cur())) params.b.w.WriteByte(OpReturn) } diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index 24e150d71a..baede3270a 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -22,7 +22,7 @@ const ( OpFillContext //15 0xf - Put reference to expression/function on stack. One parameter: position of declaration. OpPushFromFrame //16 0x10 OpPushArg //17 0x11 - Push value to frame: one param. - OpGotoArg //18 0x12 - Go to value stored in argument N: one param. + OpUseArg //18 0x12 - Go to value stored in argument N: one param. OpPushCtx //19 0x13 OpPopCtx //20 0x14 ) diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 2689603cb9..2254072510 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -76,6 +76,7 @@ type vm struct { functionName func(int) string context []args jpms []int + mem map[uint16]uint16 } func (m *vm) run() (RideResult, error) { @@ -84,6 +85,7 @@ func (m *vm) run() (RideResult, error) { } // set context, current and future m.context = append(m.context, args{}, args{}) + m.mem = make(map[uint16]uint16) //if m.calls != nil { // m.calls = m.calls[0:0] //} @@ -239,16 +241,18 @@ func (m *vm) run() (RideResult, error) { m.push(v) case OpPushArg: - arg := m.arg16() - last := len(m.context) - 1 - m.context[last] = append(m.context[last], arg) + id := m.arg16() + value := m.arg16() + m.mem[uint16(id)] = uint16(value) + //last := len(m.context) - 1 + //m.context[last] = append(m.context[last], arg) - case OpGotoArg: + case OpUseArg: argid := m.arg16() - current := len(m.context) - 2 + //current := len(m.context) - 2 m.jpms = append(m.jpms, m.ip) //m.calls = append(m.calls, newFrameContext(m.ip, m.context, m.args)) - m.ip = m.context[current][argid] + m.ip = int(m.mem[uint16(argid)]) //m.context = m.args //m.args = nil From 197130ee00f94b05099e282717e77251655e6d34 Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 5 Nov 2020 20:19:06 +0300 Subject: [PATCH 07/55] Global variables. --- go.mod | 2 +- pkg/ride/compiler2.go | 32 +++++++++++++++--- pkg/ride/compiler2_test.go | 7 ++-- pkg/ride/compiler_fsm.go | 19 ++++++++--- pkg/ride/compiler_fsm_assigment.go | 4 +++ pkg/ride/compiler_fsm_call_system.go | 15 +++++++++ pkg/ride/compiler_fsm_call_user.go | 4 +++ pkg/ride/compiler_fsm_conditional.go | 4 +++ pkg/ride/compiler_fsm_definitions.go | 17 +++++----- pkg/ride/compiler_fsm_func_declaration.go | 4 +++ pkg/ride/compiler_helpers.go | 36 ++++++++++++++++++++ pkg/ride/executable.go | 12 +++---- pkg/ride/functions_predefined.go | 40 +++++++++++++++++++++++ pkg/ride/runtime.go | 2 +- pkg/ride/vm.go | 25 -------------- pkg/ride/vm_test.go | 3 +- 16 files changed, 170 insertions(+), 56 deletions(-) create mode 100644 pkg/ride/functions_predefined.go diff --git a/go.mod b/go.mod index 04e4f148ed..74cc4d04ca 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 - github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b + github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b // indirect github.com/fxamacker/cbor/v2 v2.2.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index c812ce4303..051453bee2 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -1,6 +1,8 @@ package ride -import "github.com/pkg/errors" +import ( + "github.com/pkg/errors" +) func ccc(f Fsm, node Node) (Fsm, error) { switch n := node.(type) { @@ -50,9 +52,17 @@ func ccc(f Fsm, node Node) (Fsm, error) { return fsm, err } return ccc(fsm.Return(), n.Block) - //case *PropertyNode: - // n.Object - // n.Name + case *PropertyNode: + //f = f.Call("$property", 2) + //f, err := ccc(f, n.Object) + //if err != nil { + // return f, err + //} + //f.(params).b.writeByte(OpProperty) + + return ccc(f.Property(n.Name), n.Object) + //n.Object + //n.Name default: return f, errors.Errorf("unknown type %T", node) } @@ -72,7 +82,19 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { r := newReferences(nil) u := &uniqid{} - f := NewDefinitionsFsm(b, c, r, u, fCheck) + //predefs := newPredef() + //predefs.set("tx", math.MaxUint16, tx) + + params := params{ + b: b, + c: c, + r: r, + f: fCheck, + u: u, + predef: predefined, + } + + f := NewDefinitionsFsm(params) f, err = ccc(f, node) if err != nil { return nil, err diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 30d6cc58e7..21ee8fa08c 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/types" + "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" ) func Test_ccc(t *testing.T) { @@ -52,7 +53,7 @@ func Test_ccc(t *testing.T) { func Test22(t *testing.T) { state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return testTransferWithProofs(), nil + return byte_helpers.TransferWithProofs.Transaction, nil }} env := &MockRideEnvironment{ transactionFunc: testTransferObject, @@ -93,8 +94,8 @@ func Test22(t *testing.T) { //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, // Global variables - {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, + {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, diff --git a/pkg/ride/compiler_fsm.go b/pkg/ride/compiler_fsm.go index 53f805eeb0..4cde9a2de9 100644 --- a/pkg/ride/compiler_fsm.go +++ b/pkg/ride/compiler_fsm.go @@ -15,6 +15,7 @@ type Fsm interface { FalseBranch() Fsm Bytes(b []byte) Fsm FuncDeclaration(name string, args []string) Fsm + Property(name string) Fsm } type uniqid struct { @@ -33,16 +34,18 @@ func (a uniqid) cur() uint16 { type FunctionChecker func(string) (uint16, bool) type params struct { - // wrapper on bytes.Buffer with handy methods. + // Wrapper on bytes.Buffer with handy methods. b *builder - // slice of constants. + // Slice of constants. c *constants - // relation of variables and it's offset. + // Relation of variables and it's offset. r *references - // way to get function id. + // Way to get function id. f FunctionChecker - // unique id for func params + // Unique id for func params. u *uniqid + // Predefined variables. + predef predef } func long(f Fsm, params params, value int64) Fsm { @@ -73,6 +76,12 @@ func constant(a Fsm, params params, rideType rideType) Fsm { func reference(f Fsm, params params, name string) Fsm { pos, ok := params.r.get(name) if !ok { + if n, ok := params.predef.get(name); ok { + params.b.writeByte(OpExternalCall) + params.b.write(encode(n.id)) + params.b.write(encode(0)) + return f + } //index := params.c.put(rideString(name)) //params.b.fillContext(index) panic(fmt.Sprintf("reference %s not found", name)) diff --git a/pkg/ride/compiler_fsm_assigment.go b/pkg/ride/compiler_fsm_assigment.go index 3e3f459b5f..a687883d5c 100644 --- a/pkg/ride/compiler_fsm_assigment.go +++ b/pkg/ride/compiler_fsm_assigment.go @@ -8,6 +8,10 @@ type AssigmentFsm struct { offset uint16 } +func (a AssigmentFsm) Property(name string) Fsm { + panic("AssigmentFsm Property") +} + func (a AssigmentFsm) FuncDeclaration(name string, args []string) Fsm { return funcDeclarationFsmTransition(a, a.params, name, args) } diff --git a/pkg/ride/compiler_fsm_call_system.go b/pkg/ride/compiler_fsm_call_system.go index e3cee316c2..96535e4973 100644 --- a/pkg/ride/compiler_fsm_call_system.go +++ b/pkg/ride/compiler_fsm_call_system.go @@ -12,6 +12,17 @@ type CallSystemFsm struct { argn []uint16 } +func property(f Fsm, p params, name string) Fsm { + p.b.writeByte(OpProperty) + index := p.c.put(rideString(name)) + p.b.push(index) + return f +} + +func (a CallSystemFsm) Property(name string) Fsm { + return property(a, a.params, name) +} + func (a CallSystemFsm) FuncDeclaration(name string, args []string) Fsm { return funcDeclarationFsmTransition(a, a.params, name, args) } @@ -85,6 +96,10 @@ func (a CallSystemFsm) Return() Fsm { //a.b.startPos() n, ok := a.f(a.name) if !ok { + //if p, ok := a.predef.get(a.name); ok { + // a.b.externalCall(p.id, a.argc) + // return a.prev + //} panic(fmt.Sprintf("system function named `%s` not found", a.name)) } //for _, pos := range a.argn { diff --git a/pkg/ride/compiler_fsm_call_user.go b/pkg/ride/compiler_fsm_call_user.go index ba10cd1580..ce2f37799d 100644 --- a/pkg/ride/compiler_fsm_call_user.go +++ b/pkg/ride/compiler_fsm_call_user.go @@ -12,6 +12,10 @@ type CallUserFsm struct { argn []uint16 } +func (a CallUserFsm) Property(name string) Fsm { + panic("CallUserFsm Property") +} + func (a CallUserFsm) FuncDeclaration(name string, args []string) Fsm { return funcDeclarationFsmTransition(a, a.params, name, args) } diff --git a/pkg/ride/compiler_fsm_conditional.go b/pkg/ride/compiler_fsm_conditional.go index af766e05e9..c19db4940e 100644 --- a/pkg/ride/compiler_fsm_conditional.go +++ b/pkg/ride/compiler_fsm_conditional.go @@ -7,6 +7,10 @@ type ConditionalFsm struct { patchPosition uint16 } +func (a ConditionalFsm) Property(name string) Fsm { + panic("ConditionalFsm Property") +} + func (a ConditionalFsm) FuncDeclaration(name string, args []string) Fsm { panic("Illegal call FuncDeclaration on ConditionalFsm") } diff --git a/pkg/ride/compiler_fsm_definitions.go b/pkg/ride/compiler_fsm_definitions.go index 2a894c4290..32773ff79d 100644 --- a/pkg/ride/compiler_fsm_definitions.go +++ b/pkg/ride/compiler_fsm_definitions.go @@ -6,6 +6,13 @@ type DefinitionFsm struct { params } +func (a DefinitionFsm) Property(name string) Fsm { + a.b.writeByte(OpProperty) + index := a.params.c.put(rideString(name)) + a.params.b.push(index) + return a +} + func (a DefinitionFsm) FuncDeclaration(name string, args []string) Fsm { return funcDeclarationFsmTransition(a, a.params, name, args) } @@ -35,15 +42,9 @@ type BuildExecutable interface { BuildExecutable(version int) *Executable } -func NewDefinitionsFsm(b *builder, c *constants, r *references, u *uniqid, f FunctionChecker) Fsm { +func NewDefinitionsFsm(params params) Fsm { return &DefinitionFsm{ - params: params{ - b: b, - c: c, - r: r, - f: f, - u: u, - }, + params: params, } } diff --git a/pkg/ride/compiler_fsm_func_declaration.go b/pkg/ride/compiler_fsm_func_declaration.go index 09dfe6a156..c605f26d80 100644 --- a/pkg/ride/compiler_fsm_func_declaration.go +++ b/pkg/ride/compiler_fsm_func_declaration.go @@ -22,6 +22,10 @@ type FuncDeclarationFsm struct { globalScope *references } +func (a FuncDeclarationFsm) Property(name string) Fsm { + panic("FuncDeclarationFsm Property") +} + func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []string) Fsm { // save reference to global scope, where code lower that function will be able to use it. globalScope := params.r diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 00e6e0416b..ded03625e1 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -139,3 +139,39 @@ func (a *references) get(name string) (uint16, bool) { func (a *references) set(name string, offset uint16) { a.refs[name] = offset } + +type predefFunc struct { + id uint16 + f rideFunction +} + +type predef map[string]predefFunc + +func newPredef() predef { + return make(map[string]predefFunc) +} + +func (a predef) set(name string, id uint16, f rideFunction) { + a[name] = predefFunc{ + id: id, + f: f, + } +} + +func (a predef) get(name string) (predefFunc, bool) { + rs, ok := a[name] + return rs, ok +} + +func (a predef) iter() map[string]predefFunc { + return a +} + +func (a predef) getn(id int) rideFunction { + for _, v := range a { + if v.id == uint16(id) { + return v.f + } + } + return nil +} diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index d57f781a9f..e692d8aeaf 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -17,16 +17,14 @@ func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { if err != nil { return nil, err } - //ctx := newContext() - //ctx = ctx.add("tx", environment.transaction()) v := vm{ - code: a.ByteCode, - ip: int(a.EntryPoints[""]), - constants: a.Constants, - functions: fSelect, - //context: ctx, + code: a.ByteCode, + ip: int(a.EntryPoints[""]), + constants: a.Constants, + functions: mergeWithPredefined(fSelect, predefined), functionName: provider, + env: environment, } //v.push(environment.transaction()) diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go new file mode 100644 index 0000000000..4d62b943bd --- /dev/null +++ b/pkg/ride/functions_predefined.go @@ -0,0 +1,40 @@ +package ride + +import ( + "math" + //"github.com/pkg/errors" +) + +func tx(env RideEnvironment, _ ...rideType) (rideType, error) { + return env.transaction(), nil +} + +//func property(env RideEnvironment, args ...rideType) (rideType, error) { +// if len(args) != 2 { +// return nil, errors.Errorf("property: expected pass 2 arguments, got %d", len(args)) +// } +// name, ok := args[1].(rideString) +// if !ok { +// return nil, errors.Errorf("property: expected second argument to be string, got %T", args[1]) +// } +// +// v, err := args[0].get(string(name)) +// if err != nil { +// return nil, errors.Wrap(err, "property") +// } +// return v, nil +//} + +func mergeWithPredefined(f func(id int) rideFunction, p predef) func(id int) rideFunction { + return func(id int) rideFunction { + if c := p.getn(id); c != nil { + return c + } + return f(id) + } +} + +var predefined predef = map[string]predefFunc{ + "tx": {id: math.MaxUint16, f: tx}, + //"$property": {id: math.MaxUint16 - 1, f: property}, +} diff --git a/pkg/ride/runtime.go b/pkg/ride/runtime.go index 329c87994e..ea6bd7331c 100644 --- a/pkg/ride/runtime.go +++ b/pkg/ride/runtime.go @@ -204,7 +204,7 @@ func (a rideRecipient) instanceOf() string { func (a rideRecipient) eq(other rideType) bool { switch o := other.(type) { case rideRecipient: - return a.Address == o.Address && a.Alias == o.Alias + return proto.Recipient(a).Eq(proto.Recipient(o)) case rideAddress: return a.Address != nil && bytes.Equal(a.Address[:], o[:]) case rideAlias: diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 2254072510..f497e5b1d9 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -141,22 +141,9 @@ func (m *vm) run() (RideResult, error) { m.push(v) case OpCall: pos := m.arg16() - //cnt := m.arg16() - //in := make([]rideType, cnt) - //for i := cnt - 1; i >= 0; i-- { - // v, err := m.pop() - // if err != nil { - // return nil, errors.Wrapf(err, "failed to call function at position %d", pos) - // } - // in[i] = v - //} - //argid := m.arg16() - //m.calls = append(m.calls, newFrameContext(m.ip, m.context, m.args)) m.jpms = append(m.jpms, m.ip) m.ip = pos m.context = append(m.context, args{}) - //m.context = m.args - //m.args = nil case OpExternalCall: // Before calling external function all parameters must be evaluated and placed on stack @@ -244,23 +231,11 @@ func (m *vm) run() (RideResult, error) { id := m.arg16() value := m.arg16() m.mem[uint16(id)] = uint16(value) - //last := len(m.context) - 1 - //m.context[last] = append(m.context[last], arg) case OpUseArg: argid := m.arg16() - //current := len(m.context) - 2 m.jpms = append(m.jpms, m.ip) - //m.calls = append(m.calls, newFrameContext(m.ip, m.context, m.args)) m.ip = int(m.mem[uint16(argid)]) - //m.context = m.args - //m.args = nil - - case OpPushCtx: - m.context = append(m.context, args{}) - case OpPopCtx: - m.context = m.context[:len(m.context)-2] - m.context = append(m.context, args{}) default: return nil, errors.Errorf("unknown code %#x", op) diff --git a/pkg/ride/vm_test.go b/pkg/ride/vm_test.go index 94c3d7432a..486d9c4014 100644 --- a/pkg/ride/vm_test.go +++ b/pkg/ride/vm_test.go @@ -14,6 +14,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/types" + "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" ) //go:generate moq -pkg ride -out types_moq_test.go ../types SmartState:MockSmartState @@ -463,7 +464,7 @@ func testTransferWithProofs() *proto.TransferWithProofs { } func testTransferObject() rideObject { - obj, err := transferWithProofsToObject('T', testTransferWithProofs()) + obj, err := transferWithProofsToObject('T', byte_helpers.TransferWithProofs.Transaction) if err != nil { panic(err) } From 980f91f12dc4c0fe28cb2e71f02064ed2b75f826 Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 6 Nov 2020 13:56:32 +0300 Subject: [PATCH 08/55] Get attribute vm. --- pkg/ride/compiler2.go | 20 ++-- pkg/ride/compiler2_test.go | 14 +-- ...fsm_assigment.go => compiler_assigment.go} | 45 ++++---- ...call_system.go => compiler_call_system.go} | 41 +++---- ...fsm_call_user.go => compiler_call_user.go} | 50 +++------ pkg/ride/compiler_conditional.go | 72 +++++++++++++ pkg/ride/compiler_definitions.go | 83 +++++++++++++++ pkg/ride/compiler_fsm_conditional.go | 72 ------------- pkg/ride/compiler_fsm_definitions.go | 87 --------------- ...ration.go => compiler_func_declaration.go} | 34 +++--- pkg/ride/compiler_property.go | 70 ++++++++++++ .../{compiler_fsm.go => compiler_state.go} | 6 ++ pkg/ride/functions_predefined.go | 21 +--- pkg/ride/opcodes.go | 34 +++--- pkg/ride/vm.go | 100 ++---------------- 15 files changed, 339 insertions(+), 410 deletions(-) rename pkg/ride/{compiler_fsm_assigment.go => compiler_assigment.go} (52%) rename pkg/ride/{compiler_fsm_call_system.go => compiler_call_system.go} (64%) rename pkg/ride/{compiler_fsm_call_user.go => compiler_call_user.go} (59%) create mode 100644 pkg/ride/compiler_conditional.go create mode 100644 pkg/ride/compiler_definitions.go delete mode 100644 pkg/ride/compiler_fsm_conditional.go delete mode 100644 pkg/ride/compiler_fsm_definitions.go rename pkg/ride/{compiler_fsm_func_declaration.go => compiler_func_declaration.go} (62%) create mode 100644 pkg/ride/compiler_property.go rename pkg/ride/{compiler_fsm.go => compiler_state.go} (93%) diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 051453bee2..cc5b1c996a 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -53,16 +53,11 @@ func ccc(f Fsm, node Node) (Fsm, error) { } return ccc(fsm.Return(), n.Block) case *PropertyNode: - //f = f.Call("$property", 2) - //f, err := ccc(f, n.Object) - //if err != nil { - // return f, err - //} - //f.(params).b.writeByte(OpProperty) - - return ccc(f.Property(n.Name), n.Object) - //n.Object - //n.Name + f, err := ccc(f.Property(n.Name), n.Object) + if err != nil { + return f, err + } + return f.Return(), nil default: return f, errors.Errorf("unknown type %T", node) } @@ -82,9 +77,6 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { r := newReferences(nil) u := &uniqid{} - //predefs := newPredef() - //predefs.set("tx", math.MaxUint16, tx) - params := params{ b: b, c: c, @@ -94,7 +86,7 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { predef: predefined, } - f := NewDefinitionsFsm(params) + f := NewMain(params) f, err = ccc(f, node) if err != nil { return nil, err diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 21ee8fa08c..8133cafe06 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -95,16 +95,16 @@ func Test22(t *testing.T) { //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, // Global variables //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, - //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, nil, true}, + {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, //{`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==`, nil, true}, - //{`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, 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}, } { src, err := base64.StdEncoding.DecodeString(test.source) require.NoError(t, err, test.comment) @@ -144,8 +144,8 @@ func Test33(t *testing.T) { OpReturn, // ENTRYPOINT at(0), - OpPushArg, to(1), // jump to the beginning, first variable - OpPushArg, to(2), // jump to the second variable + OpSetArg, to(1), // jump to the beginning, first variable + OpSetArg, to(2), // jump to the second variable OpCall, 0, 8, // вызов пользовательской функции add OpReturn, ) @@ -304,7 +304,7 @@ func TestCallWithConstArg(t *testing.T) { OpReturn, OpTrue, OpReturn, - OpPushArg, 0, 1, 0, 9, + OpSetArg, 0, 1, 0, 9, OpCall, 0, 4, OpReturn, diff --git a/pkg/ride/compiler_fsm_assigment.go b/pkg/ride/compiler_assigment.go similarity index 52% rename from pkg/ride/compiler_fsm_assigment.go rename to pkg/ride/compiler_assigment.go index a687883d5c..238dde8698 100644 --- a/pkg/ride/compiler_fsm_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -1,42 +1,42 @@ package ride // Assigment: let x = 5 -type AssigmentFsm struct { +type AssigmentState struct { params prev Fsm name string offset uint16 } -func (a AssigmentFsm) Property(name string) Fsm { - panic("AssigmentFsm Property") +func (a AssigmentState) Property(name string) Fsm { + panic("AssigmentState Property") } -func (a AssigmentFsm) FuncDeclaration(name string, args []string) Fsm { +func (a AssigmentState) FuncDeclaration(name string, args []string) Fsm { return funcDeclarationFsmTransition(a, a.params, name, args) } -func (a AssigmentFsm) Bytes(b []byte) Fsm { +func (a AssigmentState) Bytes(b []byte) Fsm { return constant(a, a.params, rideBytes(b)) } -func (a AssigmentFsm) Condition() Fsm { +func (a AssigmentState) Condition() Fsm { return conditionalTransition(a, a.params) } -func (a AssigmentFsm) TrueBranch() Fsm { - panic("Illegal call `TrueBranch` on AssigmentFsm") +func (a AssigmentState) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on AssigmentState") } -func (a AssigmentFsm) FalseBranch() Fsm { - panic("Illegal call `FalseBranch` on AssigmentFsm") +func (a AssigmentState) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on AssigmentState") } -func (a AssigmentFsm) String(s string) Fsm { +func (a AssigmentState) String(s string) Fsm { return constant(a, a.params, rideString(s)) } -func (a AssigmentFsm) Boolean(v bool) Fsm { +func (a AssigmentState) Boolean(v bool) Fsm { return boolean(a, a.params, v) } @@ -45,41 +45,36 @@ func assigmentFsmTransition(prev Fsm, params params, name string) Fsm { } func newAssigmentFsm(prev Fsm, p params, name string) Fsm { - return AssigmentFsm{ - prev: prev, - params: params{ - b: p.b, - c: p.c, - f: p.f, - r: p.r, - }, + return AssigmentState{ + prev: prev, + params: p, name: name, offset: p.b.len(), } } // Create new scope, so assigment in assigment can't affect global state. -func (a AssigmentFsm) Assigment(name string) Fsm { +func (a AssigmentState) Assigment(name string) Fsm { params := a.params params.r = newReferences(params.r) return assigmentFsmTransition(a, params, name) } -func (a AssigmentFsm) Return() Fsm { +func (a AssigmentState) Return() Fsm { a.b.ret() // store reference on variable and it's offset. a.r.set(a.name, a.offset) return a.prev } -func (a AssigmentFsm) Long(value int64) Fsm { +func (a AssigmentState) Long(value int64) Fsm { return long(a, a.params, value) } -func (a AssigmentFsm) Call(name string, argc uint16) Fsm { +func (a AssigmentState) Call(name string, argc uint16) Fsm { return callTransition(a, a.params, name, argc) } -func (a AssigmentFsm) Reference(name string) Fsm { +func (a AssigmentState) Reference(name string) Fsm { return reference(a, a.params, name) } diff --git a/pkg/ride/compiler_fsm_call_system.go b/pkg/ride/compiler_call_system.go similarity index 64% rename from pkg/ride/compiler_fsm_call_system.go rename to pkg/ride/compiler_call_system.go index 96535e4973..6f0df6a8cf 100644 --- a/pkg/ride/compiler_fsm_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -3,7 +3,7 @@ package ride import "fmt" // Function call -type CallSystemFsm struct { +type CallSystemState struct { prev Fsm params name string @@ -12,42 +12,35 @@ type CallSystemFsm struct { argn []uint16 } -func property(f Fsm, p params, name string) Fsm { - p.b.writeByte(OpProperty) - index := p.c.put(rideString(name)) - p.b.push(index) - return f +func (a CallSystemState) Property(name string) Fsm { + return propertyTransition(a, a.params, name) } -func (a CallSystemFsm) Property(name string) Fsm { - return property(a, a.params, name) -} - -func (a CallSystemFsm) FuncDeclaration(name string, args []string) Fsm { +func (a CallSystemState) FuncDeclaration(name string, args []string) Fsm { return funcDeclarationFsmTransition(a, a.params, name, args) } -func (a CallSystemFsm) Bytes(b []byte) Fsm { +func (a CallSystemState) Bytes(b []byte) Fsm { return constant(a, a.params, rideBytes(b)) } -func (a CallSystemFsm) Condition() Fsm { +func (a CallSystemState) Condition() Fsm { return conditionalTransition(a, a.params) } -func (a CallSystemFsm) TrueBranch() Fsm { +func (a CallSystemState) TrueBranch() Fsm { panic("Illegal call `TrueBranch` on CallFsm") } -func (a CallSystemFsm) FalseBranch() Fsm { +func (a CallSystemState) FalseBranch() Fsm { panic("Illegal call `FalseBranch` on CallFsm") } -func (a CallSystemFsm) String(s string) Fsm { +func (a CallSystemState) String(s string) Fsm { return str(a, a.params, s) } -func (a CallSystemFsm) Boolean(v bool) Fsm { +func (a CallSystemState) Boolean(v bool) Fsm { return boolean(a, a.params, v) } @@ -59,7 +52,7 @@ func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { } func newCallSystemFsm(prev Fsm, params params, name string, argc uint16) Fsm { - return &CallSystemFsm{ + return &CallSystemState{ prev: prev, params: params, name: name, @@ -67,24 +60,24 @@ func newCallSystemFsm(prev Fsm, params params, name string, argc uint16) Fsm { } } -func (a CallSystemFsm) Assigment(name string) Fsm { +func (a CallSystemState) Assigment(name string) Fsm { return assigmentFsmTransition(a, a.params, name) } -func (a CallSystemFsm) Long(value int64) Fsm { +func (a CallSystemState) Long(value int64) Fsm { index := a.params.c.put(rideInt(value)) a.params.b.push(index) return a } -func (a CallSystemFsm) Return() Fsm { +func (a CallSystemState) Return() Fsm { //// check user functions //n, ok := a.r.get(a.name) //if ok { // a.b.startPos() // for _, pos := range a.argn { - // a.b.writeByte(OpPushArg) + // a.b.writeByte(OpSetArg) // a.b.write(encode(pos)) // //a.b.writeByte(OpReturn) // } @@ -110,10 +103,10 @@ func (a CallSystemFsm) Return() Fsm { return a.prev } -func (a CallSystemFsm) Call(name string, argc uint16) Fsm { +func (a CallSystemState) Call(name string, argc uint16) Fsm { return callTransition(a, a.params, name, argc) } -func (a CallSystemFsm) Reference(name string) Fsm { +func (a CallSystemState) Reference(name string) Fsm { return reference(a, a.params, name) } diff --git a/pkg/ride/compiler_fsm_call_user.go b/pkg/ride/compiler_call_user.go similarity index 59% rename from pkg/ride/compiler_fsm_call_user.go rename to pkg/ride/compiler_call_user.go index ce2f37799d..d2ab0eebdd 100644 --- a/pkg/ride/compiler_fsm_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -3,7 +3,7 @@ package ride import "fmt" // Function call -type CallUserFsm struct { +type CallUserState struct { prev Fsm params name string @@ -12,35 +12,35 @@ type CallUserFsm struct { argn []uint16 } -func (a CallUserFsm) Property(name string) Fsm { - panic("CallUserFsm Property") +func (a CallUserState) Property(name string) Fsm { + panic("CallUserState Property") } -func (a CallUserFsm) FuncDeclaration(name string, args []string) Fsm { +func (a CallUserState) FuncDeclaration(name string, args []string) Fsm { return funcDeclarationFsmTransition(a, a.params, name, args) } -func (a CallUserFsm) Bytes(b []byte) Fsm { +func (a CallUserState) Bytes(b []byte) Fsm { return constant(a, a.params, rideBytes(b)) } -func (a CallUserFsm) Condition() Fsm { +func (a CallUserState) Condition() Fsm { return conditionalTransition(a, a.params) } -func (a CallUserFsm) TrueBranch() Fsm { +func (a CallUserState) TrueBranch() Fsm { panic("Illegal call `TrueBranch` on CallFsm") } -func (a CallUserFsm) FalseBranch() Fsm { +func (a CallUserState) FalseBranch() Fsm { panic("Illegal call `FalseBranch` on CallFsm") } -func (a CallUserFsm) String(s string) Fsm { +func (a CallUserState) String(s string) Fsm { return str(a, a.params, s) } -func (a CallUserFsm) Boolean(v bool) Fsm { +func (a CallUserState) Boolean(v bool) Fsm { pos := a.b.len() a.b.writeByte(OpTrue) a.argn = append(a.argn, pos) @@ -53,7 +53,7 @@ func (a CallUserFsm) Boolean(v bool) Fsm { //} func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { - return &CallUserFsm{ + return &CallUserState{ prev: prev, params: params, name: name, @@ -61,11 +61,11 @@ func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { } } -func (a CallUserFsm) Assigment(name string) Fsm { +func (a CallUserState) Assigment(name string) Fsm { return assigmentFsmTransition(a, a.params, name) } -func (a CallUserFsm) Long(value int64) Fsm { +func (a CallUserState) Long(value int64) Fsm { pos := a.b.len() index := a.params.c.put(rideInt(value)) a.params.b.push(index) @@ -74,47 +74,31 @@ func (a CallUserFsm) Long(value int64) Fsm { return a } -func (a CallUserFsm) Return() Fsm { - +func (a CallUserState) Return() Fsm { // check user functions n, ok := a.r.get(a.name) if !ok { panic(fmt.Sprintf("user function `%s` not found", a.name)) } - //if ok { a.b.startPos() for i, pos := range a.argn { - a.b.writeByte(OpPushArg) + a.b.writeByte(OpSetArg) uniqid, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i)) if !ok { panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) } a.b.write(encode(uniqid)) a.b.write(encode(pos)) - //a.b.writeByte(OpReturn) } a.b.call(n, a.argc) return a.prev - //} - - //a.b.startPos() - //n, ok = a.f(a.name) - //if !ok { - // panic(fmt.Sprintf("function named %s not found", a.name)) - //} - //for _, pos := range a.argn { - // a.b.writeByte(OpJump) - // a.b.write(encode(pos)) - //} - //a.b.externalCall(n, a.argc) - //return a.prev } -func (a CallUserFsm) Call(name string, argc uint16) Fsm { +func (a CallUserState) Call(name string, argc uint16) Fsm { return callTransition(a, a.params, name, argc) } -func (a CallUserFsm) Reference(name string) Fsm { +func (a CallUserState) Reference(name string) Fsm { return reference(a, a.params, name) } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go new file mode 100644 index 0000000000..2902eeceb8 --- /dev/null +++ b/pkg/ride/compiler_conditional.go @@ -0,0 +1,72 @@ +package ride + +// If-else statement. +type ConditionalState struct { + params + prev Fsm + patchPosition uint16 +} + +func (a ConditionalState) Property(name string) Fsm { + panic("ConditionalState Property") +} + +func (a ConditionalState) FuncDeclaration(name string, args []string) Fsm { + panic("Illegal call FuncDeclaration on ConditionalState") +} + +func (a ConditionalState) Bytes(b []byte) Fsm { + return constant(a, a.params, rideBytes(b)) +} + +func conditionalTransition(prev Fsm, params params) Fsm { + return ConditionalState{ + prev: prev, + params: params, + } +} + +func (a ConditionalState) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a ConditionalState) TrueBranch() Fsm { + a.b.jpmIfFalse() + a.patchPosition = a.b.writeStub(2) + return a +} + +func (a ConditionalState) FalseBranch() Fsm { + a.b.ret() + a.b.patch(a.patchPosition, encode(a.b.len())) + return a +} + +func (a ConditionalState) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a ConditionalState) Return() Fsm { + a.b.ret() + return a.prev +} + +func (a ConditionalState) Long(value int64) Fsm { + return long(a, a.params, value) +} + +func (a ConditionalState) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a ConditionalState) Reference(name string) Fsm { + return reference(a, a.params, name) +} + +func (a ConditionalState) Boolean(v bool) Fsm { + return boolean(a, a.params, v) +} + +func (a ConditionalState) String(s string) Fsm { + return str(a, a.params, s) +} diff --git a/pkg/ride/compiler_definitions.go b/pkg/ride/compiler_definitions.go new file mode 100644 index 0000000000..ca344c79e1 --- /dev/null +++ b/pkg/ride/compiler_definitions.go @@ -0,0 +1,83 @@ +package ride + +// Initial state, contains only assigments and last expression. +type MainState struct { + params +} + +func (a MainState) Property(name string) Fsm { + return propertyTransition(a, a.params, name) +} + +func (a MainState) FuncDeclaration(name string, args []string) Fsm { + return funcDeclarationFsmTransition(a, a.params, name, args) +} + +func (a MainState) Bytes(b []byte) Fsm { + panic("Illegal call `Bytes` on `MainState`") +} + +func (a MainState) Condition() Fsm { + a.b.startPos() + return conditionalTransition(a, a.params) +} + +func (a MainState) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on MainState") +} + +func (a MainState) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on MainState") +} + +func (a MainState) String(s string) Fsm { + panic("Illegal call `String` on MainState") +} + +type BuildExecutable interface { + BuildExecutable(version int) *Executable +} + +func NewMain(params params) Fsm { + return &MainState{ + params: params, + } +} + +func (a MainState) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a MainState) Return() Fsm { + a.b.ret() + return a +} + +func (a MainState) Long(value int64) Fsm { + panic("Illegal call Long on MainState") +} + +func (a MainState) Call(name string, argc uint16) Fsm { + a.b.startPos() + return callTransition(a, a.params, name, argc) +} + +func (a MainState) Reference(name string) Fsm { + a.b.startPos() + return reference(a, a.params, name) +} + +func (a MainState) Boolean(v bool) Fsm { + a.b.startPos() + return boolean(a, a.params, v) +} + +func (a MainState) BuildExecutable(version int) *Executable { + startAt, code := a.b.build() + return &Executable{ + LibVersion: version, + ByteCode: code, + Constants: a.c.constants(), + EntryPoints: map[string]uint16{"": startAt}, + } +} diff --git a/pkg/ride/compiler_fsm_conditional.go b/pkg/ride/compiler_fsm_conditional.go deleted file mode 100644 index c19db4940e..0000000000 --- a/pkg/ride/compiler_fsm_conditional.go +++ /dev/null @@ -1,72 +0,0 @@ -package ride - -// If-else statement. -type ConditionalFsm struct { - params - prev Fsm - patchPosition uint16 -} - -func (a ConditionalFsm) Property(name string) Fsm { - panic("ConditionalFsm Property") -} - -func (a ConditionalFsm) FuncDeclaration(name string, args []string) Fsm { - panic("Illegal call FuncDeclaration on ConditionalFsm") -} - -func (a ConditionalFsm) Bytes(b []byte) Fsm { - return constant(a, a.params, rideBytes(b)) -} - -func conditionalTransition(prev Fsm, params params) Fsm { - return ConditionalFsm{ - prev: prev, - params: params, - } -} - -func (a ConditionalFsm) Condition() Fsm { - return conditionalTransition(a, a.params) -} - -func (a ConditionalFsm) TrueBranch() Fsm { - a.b.jpmIfFalse() - a.patchPosition = a.b.writeStub(2) - return a -} - -func (a ConditionalFsm) FalseBranch() Fsm { - a.b.ret() - a.b.patch(a.patchPosition, encode(a.b.len())) - return a -} - -func (a ConditionalFsm) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) -} - -func (a ConditionalFsm) Return() Fsm { - a.b.ret() - return a.prev -} - -func (a ConditionalFsm) Long(value int64) Fsm { - return long(a, a.params, value) -} - -func (a ConditionalFsm) Call(name string, argc uint16) Fsm { - return callTransition(a, a.params, name, argc) -} - -func (a ConditionalFsm) Reference(name string) Fsm { - return reference(a, a.params, name) -} - -func (a ConditionalFsm) Boolean(v bool) Fsm { - return boolean(a, a.params, v) -} - -func (a ConditionalFsm) String(s string) Fsm { - return str(a, a.params, s) -} diff --git a/pkg/ride/compiler_fsm_definitions.go b/pkg/ride/compiler_fsm_definitions.go deleted file mode 100644 index 32773ff79d..0000000000 --- a/pkg/ride/compiler_fsm_definitions.go +++ /dev/null @@ -1,87 +0,0 @@ -package ride - -// Initial state, contains only assigments and last expression. -// TODO chose better name -type DefinitionFsm struct { - params -} - -func (a DefinitionFsm) Property(name string) Fsm { - a.b.writeByte(OpProperty) - index := a.params.c.put(rideString(name)) - a.params.b.push(index) - return a -} - -func (a DefinitionFsm) FuncDeclaration(name string, args []string) Fsm { - return funcDeclarationFsmTransition(a, a.params, name, args) -} - -func (a DefinitionFsm) Bytes(b []byte) Fsm { - panic("Illegal call `Bytes` on `DefinitionFsm`") -} - -func (a DefinitionFsm) Condition() Fsm { - a.b.startPos() - return conditionalTransition(a, a.params) -} - -func (a DefinitionFsm) TrueBranch() Fsm { - panic("Illegal call `TrueBranch` on DefinitionFsm") -} - -func (a DefinitionFsm) FalseBranch() Fsm { - panic("Illegal call `FalseBranch` on DefinitionFsm") -} - -func (a DefinitionFsm) String(s string) Fsm { - panic("Illegal call `String` on DefinitionFsm") -} - -type BuildExecutable interface { - BuildExecutable(version int) *Executable -} - -func NewDefinitionsFsm(params params) Fsm { - return &DefinitionFsm{ - params: params, - } -} - -func (a DefinitionFsm) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) -} - -func (a DefinitionFsm) Return() Fsm { - a.b.ret() - return a -} - -func (a DefinitionFsm) Long(value int64) Fsm { - panic("Illegal call Long on DefinitionFsm") -} - -func (a DefinitionFsm) Call(name string, argc uint16) Fsm { - a.b.startPos() - return callTransition(a, a.params, name, argc) -} - -func (a DefinitionFsm) Reference(name string) Fsm { - a.b.startPos() - return reference(a, a.params, name) -} - -func (a DefinitionFsm) Boolean(v bool) Fsm { - a.b.startPos() - return boolean(a, a.params, v) -} - -func (a DefinitionFsm) BuildExecutable(version int) *Executable { - startAt, code := a.b.build() - return &Executable{ - LibVersion: version, - ByteCode: code, - Constants: a.c.constants(), - EntryPoints: map[string]uint16{"": startAt}, - } -} diff --git a/pkg/ride/compiler_fsm_func_declaration.go b/pkg/ride/compiler_func_declaration.go similarity index 62% rename from pkg/ride/compiler_fsm_func_declaration.go rename to pkg/ride/compiler_func_declaration.go index c605f26d80..c099db1e16 100644 --- a/pkg/ride/compiler_fsm_func_declaration.go +++ b/pkg/ride/compiler_func_declaration.go @@ -13,7 +13,7 @@ func (a arguments) pos(name string) int { return -1 } -type FuncDeclarationFsm struct { +type FuncDeclarationState struct { params prev Fsm name string @@ -22,8 +22,8 @@ type FuncDeclarationFsm struct { globalScope *references } -func (a FuncDeclarationFsm) Property(name string) Fsm { - panic("FuncDeclarationFsm Property") +func (a FuncDeclarationState) Property(name string) Fsm { + panic("FuncDeclarationState Property") } func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []string) Fsm { @@ -41,7 +41,7 @@ func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []s params.b.w.WriteByte(OpReturn) } - return &FuncDeclarationFsm{ + return &FuncDeclarationState{ prev: prev, name: name, args: args, @@ -51,55 +51,55 @@ func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []s } } -func (a FuncDeclarationFsm) Assigment(name string) Fsm { +func (a FuncDeclarationState) Assigment(name string) Fsm { return assigmentFsmTransition(a, a.params, name) } -func (a FuncDeclarationFsm) Return() Fsm { +func (a FuncDeclarationState) Return() Fsm { a.globalScope.set(a.name, a.offset) a.b.writeByte(OpPopCtx) a.b.ret() return a.prev } -func (a FuncDeclarationFsm) Long(value int64) Fsm { +func (a FuncDeclarationState) Long(value int64) Fsm { index := a.params.c.put(rideInt(value)) a.params.b.push(index) return a } -func (a FuncDeclarationFsm) Call(name string, argc uint16) Fsm { +func (a FuncDeclarationState) Call(name string, argc uint16) Fsm { return callTransition(a, a.params, name, argc) } -func (a FuncDeclarationFsm) Reference(name string) Fsm { +func (a FuncDeclarationState) Reference(name string) Fsm { return reference(a, a.params, name) } -func (a FuncDeclarationFsm) Boolean(v bool) Fsm { +func (a FuncDeclarationState) Boolean(v bool) Fsm { panic("implement me") } -func (a FuncDeclarationFsm) String(s string) Fsm { +func (a FuncDeclarationState) String(s string) Fsm { panic("implement me") } -func (a FuncDeclarationFsm) Condition() Fsm { +func (a FuncDeclarationState) Condition() Fsm { return conditionalTransition(a, a.params) } -func (a FuncDeclarationFsm) TrueBranch() Fsm { +func (a FuncDeclarationState) TrueBranch() Fsm { panic("implement me") } -func (a FuncDeclarationFsm) FalseBranch() Fsm { +func (a FuncDeclarationState) FalseBranch() Fsm { panic("implement me") } -func (a FuncDeclarationFsm) Bytes(b []byte) Fsm { +func (a FuncDeclarationState) Bytes(b []byte) Fsm { panic("implement me") } -func (a FuncDeclarationFsm) FuncDeclaration(name string, args []string) Fsm { - panic("Illegal call `FuncDeclaration` is `FuncDeclarationFsm`") +func (a FuncDeclarationState) FuncDeclaration(name string, args []string) Fsm { + panic("Illegal call `FuncDeclaration` is `FuncDeclarationState`") } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go new file mode 100644 index 0000000000..9dbb450fda --- /dev/null +++ b/pkg/ride/compiler_property.go @@ -0,0 +1,70 @@ +package ride + +type PropertyState struct { + prev Fsm + name string + params +} + +func propertyTransition(prev Fsm, params params, name string) Fsm { + return &PropertyState{ + params: params, + prev: prev, + name: name, + } +} + +func (a PropertyState) Assigment(name string) Fsm { + panic("Illegal call `Assigment` on PropertyState") +} + +func (a PropertyState) Return() Fsm { + a.b.writeByte(OpProperty) + index := a.params.c.put(rideString(a.name)) + a.params.b.write(encode(index)) + return a.prev +} + +func (a PropertyState) Long(value int64) Fsm { + panic("Illegal call `Long` on PropertyState") +} + +func (a PropertyState) Call(name string, argc uint16) Fsm { + panic("Illegal call `Call` on PropertyState") +} + +func (a PropertyState) Reference(name string) Fsm { + return reference(a, a.params, name) +} + +func (a PropertyState) Boolean(v bool) Fsm { + panic("Illegal call `Boolean` on PropertyState") +} + +func (a PropertyState) String(s string) Fsm { + panic("Illegal call `String` on PropertyState") +} + +func (a PropertyState) Condition() Fsm { + panic("Illegal call `Condition` on PropertyState") +} + +func (a PropertyState) TrueBranch() Fsm { + panic("Illegal call `TrueBranch` on PropertyState") +} + +func (a PropertyState) FalseBranch() Fsm { + panic("Illegal call `FalseBranch` on PropertyState") +} + +func (a PropertyState) Bytes(b []byte) Fsm { + return bts(a, a.params, b) +} + +func (a PropertyState) FuncDeclaration(name string, args []string) Fsm { + panic("Illegal call `FuncDeclaration` on PropertyState") +} + +func (a PropertyState) Property(name string) Fsm { + panic("Illegal call `Property` on PropertyState") +} diff --git a/pkg/ride/compiler_fsm.go b/pkg/ride/compiler_state.go similarity index 93% rename from pkg/ride/compiler_fsm.go rename to pkg/ride/compiler_state.go index 4cde9a2de9..b7129276ce 100644 --- a/pkg/ride/compiler_fsm.go +++ b/pkg/ride/compiler_state.go @@ -60,6 +60,12 @@ func boolean(f Fsm, params params, value bool) Fsm { return f } +func bts(f Fsm, params params, value []byte) Fsm { + index := params.c.put(rideBytes(value)) + params.b.push(index) + return f +} + func str(a Fsm, params params, s string) Fsm { index := params.c.put(rideString(s)) params.b.push(index) diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index 4d62b943bd..5c0d2797a5 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -9,22 +9,6 @@ func tx(env RideEnvironment, _ ...rideType) (rideType, error) { return env.transaction(), nil } -//func property(env RideEnvironment, args ...rideType) (rideType, error) { -// if len(args) != 2 { -// return nil, errors.Errorf("property: expected pass 2 arguments, got %d", len(args)) -// } -// name, ok := args[1].(rideString) -// if !ok { -// return nil, errors.Errorf("property: expected second argument to be string, got %T", args[1]) -// } -// -// v, err := args[0].get(string(name)) -// if err != nil { -// return nil, errors.Wrap(err, "property") -// } -// return v, nil -//} - func mergeWithPredefined(f func(id int) rideFunction, p predef) func(id int) rideFunction { return func(id int) rideFunction { if c := p.getn(id); c != nil { @@ -35,6 +19,7 @@ func mergeWithPredefined(f func(id int) rideFunction, p predef) func(id int) rid } var predefined predef = map[string]predefFunc{ - "tx": {id: math.MaxUint16, f: tx}, - //"$property": {id: math.MaxUint16 - 1, f: property}, + "tx": {id: math.MaxUint16 - 0, f: tx}, + "unit": {id: math.MaxUint16 - 1, f: unit}, + "NOALG": {id: math.MaxUint16 - 2, f: createNoAlg}, } diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index baede3270a..2a96f0e7b1 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -4,25 +4,17 @@ package ride // Parameter is 2 bytes length const ( - OpHalt byte = iota //00 - Halts program execution. No parameters. - OpReturn //01 - Returns from declaration to stored position. No parameters. - OpPush //02 - Put constant on stack. One parameter: constant ID. - OpPop //03 - Removes value from stack. No parameters. - OpTrue //04 - Put True value on stack. No parameters. - OpFalse //05 - Put False value on stack. No parameters. - OpJump //06 - Moves instruction pointer to new position. One parameter: new position. - OpJumpIfFalse //07 - Moves instruction pointer to new position if value on stack is False. One parameter: new position. - OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. - OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. - OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. - OpGlobal //11 0xb - Load global constant. One parameter: global constant ID. - OpLoad //12 0xc - Evaluates an expression that declared at address. One parameter: position of declaration. - OpLoadLocal //13 0xd - Load an argument of function call on stack. One parameter: argument number. - OpRef //14 0xe - Put reference to expression/function on stack. One parameter: position of declaration. - OpFillContext //15 0xf - Put reference to expression/function on stack. One parameter: position of declaration. - OpPushFromFrame //16 0x10 - OpPushArg //17 0x11 - Push value to frame: one param. - OpUseArg //18 0x12 - Go to value stored in argument N: one param. - OpPushCtx //19 0x13 - OpPopCtx //20 0x14 + OpHalt byte = iota //00 - Halts program execution. No parameters. + OpReturn //01 - Returns from declaration to stored position. No parameters. + OpPush //02 - Put constant on stack. One parameter: constant ID. + OpPop //03 - Removes value from stack. No parameters. + OpTrue //04 - Put True value on stack. No parameters. + OpFalse //05 - Put False value on stack. No parameters. + OpJump //06 - Moves instruction pointer to new position. One parameter: new position. + OpJumpIfFalse //07 - Moves instruction pointer to new position if value on stack is False. One parameter: new position. + OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. + OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. + OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. + OpSetArg //11 0xb - Set value into cell. Two parameters: constant id and cell id. + OpUseArg //12 0xc - Use stored value in cell. One param: cell id. ) diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index f497e5b1d9..7ee0ca6f23 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -65,16 +65,14 @@ func newFrameContext(pos int, context args, future args) frame { type args = []int type vm struct { - env RideEnvironment - code []byte - ip int - constants []rideType - functions func(int) rideFunction - globals func(int) rideConstructor - stack []rideType - //calls []frame + env RideEnvironment + code []byte + ip int + constants []rideType + functions func(int) rideFunction + globals func(int) rideConstructor + stack []rideType functionName func(int) string - context []args jpms []int mem map[uint16]uint16 } @@ -83,13 +81,7 @@ func (m *vm) run() (RideResult, error) { if m.stack != nil { m.stack = m.stack[0:0] } - // set context, current and future - m.context = append(m.context, args{}, args{}) m.mem = make(map[uint16]uint16) - //if m.calls != nil { - // m.calls = m.calls[0:0] - //} - //m.ip = 0 for m.ip < len(m.code) { op := m.code[m.ip] m.ip++ @@ -107,10 +99,8 @@ func (m *vm) run() (RideResult, error) { m.push(rideBoolean(false)) case OpJump: pos := m.arg16() - //current := m.ip m.jpms = append(m.jpms, m.ip) m.ip = pos - //m.calls = append(m.calls, newExpressionFrame(current)) case OpJumpIfFalse: pos := m.arg16() val, err := m.pop() @@ -143,7 +133,6 @@ func (m *vm) run() (RideResult, error) { pos := m.arg16() m.jpms = append(m.jpms, m.ip) m.ip = pos - m.context = append(m.context, args{}) case OpExternalCall: // Before calling external function all parameters must be evaluated and placed on stack @@ -166,25 +155,6 @@ func (m *vm) run() (RideResult, error) { return nil, err } m.push(res) - //case OpLoad: // Evaluate expression behind a LET declaration - // pos := m.arg16() - // frame := newExpressionFrame(m.ip) // Creating new function frame with return position - // m.calls = append(m.calls, frame) - // m.ip = pos // Continue to expression - //case OpLoadLocal: - // n := m.arg16() - // for i := len(m.calls) - 1; i >= 0; i-- { - // - // } - // l := len(m.calls) - // if l == 0 { - // return nil, errors.New("failed to load argument on stack") - // } - // frame := m.calls[l-1] - // if l := len(frame.args); l < n+1 { - // return nil, errors.New("invalid arguments count") - // } - // m.push(frame.args[n]) case OpReturn: l := len(m.jpms) if l == 0 { @@ -202,32 +172,9 @@ func (m *vm) run() (RideResult, error) { } return nil, errors.New("no result after script execution") } - //var f frame m.ip, m.jpms = m.jpms[l-1], m.jpms[:l-1] - //m.ip = m.jpms[l-1] - //m.context = f.context - //m.args = f.future - //case OpHalt: - // if len(m.stack) > 0 { - // v, err := m.pop() - // if err != nil { - // return nil, errors.Wrap(err, "failed to get result value") - // } - // switch tv := v.(type) { - // case rideBoolean: - // return ScriptResult{res: bool(tv)}, nil - // default: - // return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) - // } - // } - // return nil, errors.New("no result after script execution") - case OpGlobal: - id := m.arg16() - constructor := m.globals(id) - v := constructor(m.env) - m.push(v) - case OpPushArg: + case OpSetArg: id := m.arg16() value := m.arg16() m.mem[uint16(id)] = uint16(value) @@ -244,16 +191,6 @@ func (m *vm) run() (RideResult, error) { return nil, errors.New("broken code") } -//func (m *vm) goTo(pos int) { -// f := m.nextFrame -// f.back = pos -// -// m.calls = append(m.calls, f) -// m.ip = pos // Continue to function -// m.args = m.curFrame -// m.curFrame = m.nextFrame -//} - func (m *vm) push(v rideType) constid { m.stack = append(m.stack, v) return uint16(len(m.stack) - 1) @@ -283,24 +220,3 @@ func (m *vm) constant() rideType { //TODO: add check return m.constants[m.arg16()] } - -//func (m *vm) scope() (*frame, int) { -// n := len(m.calls) - 1 -// if n < 0 { -// return nil, n -// } -// return &m.calls[n], n -//} - -//func (m *vm) resolve(name string) (int, error) { -// _ = name -// //TODO: implement -// return 0, errors.New("not implemented") -//} - -//func (m *vm) returnPosition() int { -// if l := len(m.calls); l > 0 { -// return m.calls[l-1].back -// } -// return len(m.code) -//} From b11b59e135c59535fa12dc0f115c7d5357a31775 Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 6 Nov 2020 16:43:58 +0300 Subject: [PATCH 09/55] Odd byte codes. --- pkg/ride/opcodes.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index 2a96f0e7b1..b00abf7446 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -17,4 +17,9 @@ const ( OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. OpSetArg //11 0xb - Set value into cell. Two parameters: constant id and cell id. OpUseArg //12 0xc - Use stored value in cell. One param: cell id. + + // odd, will be removed. + OpGlobal + OpLoadLocal + OpLoad ) From 3f70cd3d9bed5dfcfa0564a3cf9807c4e92b6382 Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 10 Nov 2020 18:34:25 +0300 Subject: [PATCH 10/55] Stagenet tests. --- go.mod | 2 +- pkg/ride/compiler2.go | 5 +- pkg/ride/compiler2_test.go | 210 +++++++++++++++++- pkg/ride/compiler_assigment.go | 4 +- pkg/ride/compiler_call_system.go | 4 +- pkg/ride/compiler_call_user.go | 17 +- pkg/ride/compiler_conditional.go | 4 +- pkg/ride/compiler_func.go | 130 +++++++++++ pkg/ride/compiler_func_declaration.go | 105 --------- pkg/ride/compiler_helpers.go | 47 ++-- ...mpiler_definitions.go => compiler_main.go} | 6 +- pkg/ride/compiler_property.go | 4 +- pkg/ride/compiler_state.go | 14 +- pkg/ride/functions_predefined.go | 18 +- pkg/ride/tree_evaluation.go | 10 +- pkg/ride/tree_evaluator.go | 1 + pkg/ride/vm.go | 82 ++----- pkg/state/script_caller.go | 2 + pkg/state/scripts_storage.go | 2 + pkg/state/transaction_checker.go | 2 +- 20 files changed, 452 insertions(+), 217 deletions(-) create mode 100644 pkg/ride/compiler_func.go delete mode 100644 pkg/ride/compiler_func_declaration.go rename pkg/ride/{compiler_definitions.go => compiler_main.go} (90%) diff --git a/go.mod b/go.mod index 74cc4d04ca..04e4f148ed 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 - github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b // indirect + github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b github.com/fxamacker/cbor/v2 v2.2.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index cc5b1c996a..9e46687705 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -47,7 +47,7 @@ func ccc(f Fsm, node Node) (Fsm, error) { } return f.Return(), nil case *FunctionDeclarationNode: - fsm, err := ccc(f.FuncDeclaration(n.Name, n.Arguments), n.Body) + fsm, err := ccc(f.Func(n.Name, n.Arguments, n.invocationParameter), n.Body) if err != nil { return fsm, err } @@ -58,6 +58,9 @@ func ccc(f Fsm, node Node) (Fsm, error) { return f, err } return f.Return(), nil + case nil: + // it should be dapp + return f, nil default: return f, errors.Errorf("unknown type %T", node) } diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 8133cafe06..784ae12602 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -3,6 +3,8 @@ package ride import ( "bytes" "encoding/base64" + "fmt" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -259,7 +261,6 @@ func TestDoubleCall(t *testing.T) { require.Equal(t, []byte{ OpPush, 0, 0, - OpPopCtx, OpReturn, OpCall, 0, 0, @@ -300,10 +301,11 @@ func TestCallWithConstArg(t *testing.T) { []byte{ OpUseArg, 0, 1, OpReturn, // arguments section OpJump, 0, 0, // Function execution code. One line: reference to `v` argument. - OpPopCtx, OpReturn, - OpTrue, OpReturn, + OpTrue, OpReturn, // define constant + + // call function OpSetArg, 0, 1, 0, 9, OpCall, 0, 4, @@ -315,3 +317,205 @@ func TestCallWithConstArg(t *testing.T) { 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 TestCompileDapp(t *testing.T) { + source := "AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==" + state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }} + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileSimpleScript(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + res, err := script.Run(env) + require.NoError(t, err) + assert.NotNil(t, res) + r, ok := res.(ScriptResult) + assert.True(t, ok) + assert.Equal(t, true, r.Result()) +} + +/* + + +base64:AwoBAAAAAWYAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBwAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAWEFAAAAByRtYXRjaDAAAAAAAAAAAAEAAAAAAAAAAAAEAAAAAWEJAQAAAAFmAAAAAQIAAAABYQQAAAABYgkBAAAAAWYAAAABAgAAAAFiBAAAAAFjCQEAAAABZgAAAAECAAAAAWMEAAAAAWQJAQAAAAFmAAAAAQIAAAABZAQAAAABZQkBAAAAAWYAAAABAgAAAAFlAwkAAAAAAAACCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIFAAAAAWEFAAAAAWIFAAAAAWMFAAAAAWQFAAAAAWUAAAAAAAAAAAUJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V5B4xspLY= + + +*/ + +func Test2121(t *testing.T) { + source := `AwoBAAAAAWYAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBwAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAWEFAAAAByRtYXRjaDAAAAAAAAAAAAEAAAAAAAAAAAAEAAAAAWEJAQAAAAFmAAAAAQIAAAABYQQAAAABYgkBAAAAAWYAAAABAgAAAAFiBAAAAAFjCQEAAAABZgAAAAECAAAAAWMEAAAAAWQJAQAAAAFmAAAAAQIAAAABZAQAAAABZQkBAAAAAWYAAAABAgAAAAFlAwkAAAAAAAACCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIFAAAAAWEFAAAAAWIFAAAAAWMFAAAAAWQFAAAAAWUAAAAAAAAAAAUJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V5B4xspLY=` + state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }} + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + thisFunc: func() rideType { + return testTransferObject() + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + t.Log(detree(tree.Verifier)) + + script, err := CompileSimpleScript(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + res, err := script.Run(env) + require.NoError(t, err) + assert.NotNil(t, res) + r, ok := res.(ScriptResult) + assert.True(t, ok) + assert.Equal(t, true, r.Result()) +} + +func detree(tree Node) string { + s := &strings.Builder{} + detree_(s, tree, 0) + return s.String() +} + +func detree_(s *strings.Builder, tree Node, shift int) { + switch n := tree.(type) { + case *FunctionDeclarationNode: + s.WriteString(fmt.Sprintf("func %s(", n.Name)) + for _, a := range n.Arguments { + s.WriteString(a) + s.WriteString(",") + } + s.WriteString(") {\n") + s.WriteString(strings.Repeat(" ", shift+1)) + detree_(s, n.Body, shift+1) + s.WriteString("}\n") + detree_(s, n.Block, shift) + + case *AssignmentNode: + s.WriteString(fmt.Sprintf("let %s = ", n.Name)) + detree_(s, n.Expression, shift) + s.WriteString("\n") + detree_(s, n.Block, shift) + + case *ConditionalNode: + s.WriteString(strings.Repeat(" ", shift*4)) + s.WriteString(fmt.Sprintf("if (")) + detree_(s, n.Condition, shift) + s.WriteString(") {\n") + s.WriteString(strings.Repeat(" ", (shift+1)*4)) + detree_(s, n.TrueExpression, shift+1) + s.WriteString("} else {\n") + s.WriteString(strings.Repeat(" ", (shift+1)*4)) + detree_(s, n.FalseExpression, shift+1) + s.WriteString("}\n") + case *FunctionCallNode: + s.WriteString(n.Name) + s.WriteString("(") + for _, a := range n.Arguments { + detree_(s, a, shift) + s.WriteString(",") + } + s.WriteString(")") + case *ReferenceNode: + s.WriteString(n.Name) + case *StringNode: + s.WriteString(`"`) + s.WriteString(n.Value) + s.WriteString(`"`) + case *PropertyNode: + detree_(s, n.Object, shift) + s.WriteString(".") + s.WriteString(n.Name) + case *BooleanNode: + s.WriteString(fmt.Sprintf("%t", n.Value)) + case *LongNode: + s.WriteString(fmt.Sprintf("%d", n.Value)) + default: + panic(fmt.Sprintf("unknown type %T", n)) + } + //return s.String() +} diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 238dde8698..824eee47fd 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -12,8 +12,8 @@ func (a AssigmentState) Property(name string) Fsm { panic("AssigmentState Property") } -func (a AssigmentState) FuncDeclaration(name string, args []string) Fsm { - return funcDeclarationFsmTransition(a, a.params, name, args) +func (a AssigmentState) Func(name string, args []string, invoke string) Fsm { + return funcTransition(a, a.params, name, args, invoke) } func (a AssigmentState) Bytes(b []byte) Fsm { diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 6f0df6a8cf..d661fea43f 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -16,8 +16,8 @@ func (a CallSystemState) Property(name string) Fsm { return propertyTransition(a, a.params, name) } -func (a CallSystemState) FuncDeclaration(name string, args []string) Fsm { - return funcDeclarationFsmTransition(a, a.params, name, args) +func (a CallSystemState) Func(name string, args []string, invoke string) Fsm { + return funcTransition(a, a.params, name, args, invoke) } func (a CallSystemState) Bytes(b []byte) Fsm { diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index d2ab0eebdd..c3b9481e9d 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -16,12 +16,14 @@ func (a CallUserState) Property(name string) Fsm { panic("CallUserState Property") } -func (a CallUserState) FuncDeclaration(name string, args []string) Fsm { - return funcDeclarationFsmTransition(a, a.params, name, args) +func (a CallUserState) Func(name string, args []string, invoke string) Fsm { + return funcTransition(a, a.params, name, args, invoke) } func (a CallUserState) Bytes(b []byte) Fsm { - return constant(a, a.params, rideBytes(b)) + a.argn = append(a.argn, putConstant(a.params, rideBytes(b))) + a.b.ret() + return a } func (a CallUserState) Condition() Fsm { @@ -37,7 +39,9 @@ func (a CallUserState) FalseBranch() Fsm { } func (a CallUserState) String(s string) Fsm { - return str(a, a.params, s) + a.argn = append(a.argn, putConstant(a.params, rideString(s))) + a.b.ret() + return a } func (a CallUserState) Boolean(v bool) Fsm { @@ -66,10 +70,7 @@ func (a CallUserState) Assigment(name string) Fsm { } func (a CallUserState) Long(value int64) Fsm { - pos := a.b.len() - index := a.params.c.put(rideInt(value)) - a.params.b.push(index) - a.argn = append(a.argn, pos) + a.argn = append(a.argn, putConstant(a.params, rideInt(value))) a.b.ret() return a } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 2902eeceb8..40cec2360c 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -11,8 +11,8 @@ func (a ConditionalState) Property(name string) Fsm { panic("ConditionalState Property") } -func (a ConditionalState) FuncDeclaration(name string, args []string) Fsm { - panic("Illegal call FuncDeclaration on ConditionalState") +func (a ConditionalState) Func(name string, args []string, invoke string) Fsm { + panic("Illegal call Func on ConditionalState") } func (a ConditionalState) Bytes(b []byte) Fsm { diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go new file mode 100644 index 0000000000..63dcec0bbc --- /dev/null +++ b/pkg/ride/compiler_func.go @@ -0,0 +1,130 @@ +package ride + +import ( + "fmt" + "math" +) + +type arguments []string + +func (a arguments) pos(name string) int { + for i := range a { + if a[i] == name { + return i + } + } + return -1 +} + +type FuncState struct { + params + prev Fsm + name string + args arguments + offset uint16 + globalScope *references + invokeParam string +} + +func (a FuncState) Property(name string) Fsm { + panic("FuncState Property") +} + +func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { + // save reference to global scope, where code lower that function will be able to use it. + globalScope := params.r + // all variable we add only visible to current scope, + // avoid corrupting parent state. + params.r = newReferences(params.r) + for i := range args { + params.r.set(args[i], params.b.len()) + // set to global + globalScope.set(fmt.Sprintf("%s$%d", name, i), params.u.next()) + params.b.w.WriteByte(OpUseArg) + params.b.w.Write(encode(params.u.cur())) + params.b.w.WriteByte(OpReturn) + } + // assume that it's verifier + if invokeParam != "" { + // tx + params.predef = newPredefWithValue(params.predef, "tx", math.MaxUint16, tx) + pos := params.b.len() + params.b.writeByte(OpExternalCall) + params.b.write(encode(math.MaxUint16)) + params.b.write(encode(0)) + params.b.writeByte(OpReturn) + params.r.set(invokeParam, pos) + } + + return &FuncState{ + prev: prev, + name: name, + args: args, + params: params, + offset: params.b.len(), + globalScope: globalScope, + invokeParam: invokeParam, + } +} + +func (a FuncState) Assigment(name string) Fsm { + return assigmentFsmTransition(a, a.params, name) +} + +func (a FuncState) Return() Fsm { + a.globalScope.set(a.name, a.offset) + // TODO clean args + //a.b.writeByte(OpPopCtx) + a.b.ret() + + // if function has invoke param, it means no other code will be provided. + if a.invokeParam != "" { + a.b.startPos() + a.b.writeByte(OpCall) + a.b.write(encode(a.offset)) + } + + return a.prev +} + +func (a FuncState) Long(value int64) Fsm { + index := a.params.c.put(rideInt(value)) + a.params.b.push(index) + return a +} + +func (a FuncState) Call(name string, argc uint16) Fsm { + return callTransition(a, a.params, name, argc) +} + +func (a FuncState) Reference(name string) Fsm { + return reference(a, a.params, name) +} + +func (a FuncState) Boolean(v bool) Fsm { + panic("implement me") +} + +func (a FuncState) String(s string) Fsm { + panic("implement me") +} + +func (a FuncState) Condition() Fsm { + return conditionalTransition(a, a.params) +} + +func (a FuncState) TrueBranch() Fsm { + panic("implement me") +} + +func (a FuncState) FalseBranch() Fsm { + panic("implement me") +} + +func (a FuncState) Bytes(b []byte) Fsm { + panic("implement me") +} + +func (a FuncState) Func(name string, args []string, _ string) Fsm { + panic("Illegal call `Func` is `FuncState`") +} diff --git a/pkg/ride/compiler_func_declaration.go b/pkg/ride/compiler_func_declaration.go deleted file mode 100644 index c099db1e16..0000000000 --- a/pkg/ride/compiler_func_declaration.go +++ /dev/null @@ -1,105 +0,0 @@ -package ride - -import "fmt" - -type arguments []string - -func (a arguments) pos(name string) int { - for i := range a { - if a[i] == name { - return i - } - } - return -1 -} - -type FuncDeclarationState struct { - params - prev Fsm - name string - args arguments - offset uint16 - globalScope *references -} - -func (a FuncDeclarationState) Property(name string) Fsm { - panic("FuncDeclarationState Property") -} - -func funcDeclarationFsmTransition(prev Fsm, params params, name string, args []string) Fsm { - // save reference to global scope, where code lower that function will be able to use it. - globalScope := params.r - //// all variable we add only visible to current scope, - //// avoid corrupting parent state. - params.r = newReferences(params.r) - for i := range args { - params.r.set(args[i], params.b.len()) - // set to global - globalScope.set(fmt.Sprintf("%s$%d", name, i), params.u.next()) - params.b.w.WriteByte(OpUseArg) - params.b.w.Write(encode(params.u.cur())) - params.b.w.WriteByte(OpReturn) - } - - return &FuncDeclarationState{ - prev: prev, - name: name, - args: args, - params: params, - offset: params.b.len(), - globalScope: globalScope, - } -} - -func (a FuncDeclarationState) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) -} - -func (a FuncDeclarationState) Return() Fsm { - a.globalScope.set(a.name, a.offset) - a.b.writeByte(OpPopCtx) - a.b.ret() - return a.prev -} - -func (a FuncDeclarationState) Long(value int64) Fsm { - index := a.params.c.put(rideInt(value)) - a.params.b.push(index) - return a -} - -func (a FuncDeclarationState) Call(name string, argc uint16) Fsm { - return callTransition(a, a.params, name, argc) -} - -func (a FuncDeclarationState) Reference(name string) Fsm { - return reference(a, a.params, name) -} - -func (a FuncDeclarationState) Boolean(v bool) Fsm { - panic("implement me") -} - -func (a FuncDeclarationState) String(s string) Fsm { - panic("implement me") -} - -func (a FuncDeclarationState) Condition() Fsm { - return conditionalTransition(a, a.params) -} - -func (a FuncDeclarationState) TrueBranch() Fsm { - panic("implement me") -} - -func (a FuncDeclarationState) FalseBranch() Fsm { - panic("implement me") -} - -func (a FuncDeclarationState) Bytes(b []byte) Fsm { - panic("implement me") -} - -func (a FuncDeclarationState) FuncDeclaration(name string, args []string) Fsm { - panic("Illegal call `FuncDeclaration` is `FuncDeclarationState`") -} diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index ded03625e1..619eafdcec 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -145,33 +145,50 @@ type predefFunc struct { f rideFunction } -type predef map[string]predefFunc +type predef struct { + prev *predef + m map[string]predefFunc +} -func newPredef() predef { - return make(map[string]predefFunc) +func newPredef(prev *predef) *predef { + return &predef{ + prev: prev, + m: make(map[string]predefFunc), + } } -func (a predef) set(name string, id uint16, f rideFunction) { - a[name] = predefFunc{ +func newPredefWithValue(prev *predef, name string, id uint16, f rideFunction) *predef { + p := newPredef(prev) + p.set(name, id, f) + return p +} + +func (a *predef) set(name string, id uint16, f rideFunction) { + a.m[name] = predefFunc{ id: id, f: f, } } -func (a predef) get(name string) (predefFunc, bool) { - rs, ok := a[name] - return rs, ok -} - -func (a predef) iter() map[string]predefFunc { - return a +func (a *predef) get(name string) (predefFunc, bool) { + if a == nil { + return predefFunc{}, false + } + rs, ok := a.m[name] + if ok { + return rs, ok + } + return a.prev.get(name) } -func (a predef) getn(id int) rideFunction { - for _, v := range a { +func (a *predef) getn(id int) rideFunction { + if a == nil { + return nil + } + for _, v := range a.m { if v.id == uint16(id) { return v.f } } - return nil + return a.prev.getn(id) } diff --git a/pkg/ride/compiler_definitions.go b/pkg/ride/compiler_main.go similarity index 90% rename from pkg/ride/compiler_definitions.go rename to pkg/ride/compiler_main.go index ca344c79e1..8fc7979b8d 100644 --- a/pkg/ride/compiler_definitions.go +++ b/pkg/ride/compiler_main.go @@ -9,8 +9,8 @@ func (a MainState) Property(name string) Fsm { return propertyTransition(a, a.params, name) } -func (a MainState) FuncDeclaration(name string, args []string) Fsm { - return funcDeclarationFsmTransition(a, a.params, name, args) +func (a MainState) Func(name string, args []string, invoke string) Fsm { + return funcTransition(a, a.params, name, args, invoke) } func (a MainState) Bytes(b []byte) Fsm { @@ -53,7 +53,7 @@ func (a MainState) Return() Fsm { return a } -func (a MainState) Long(value int64) Fsm { +func (a MainState) Long(int64) Fsm { panic("Illegal call Long on MainState") } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 9dbb450fda..fd3b4ba28d 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -61,8 +61,8 @@ func (a PropertyState) Bytes(b []byte) Fsm { return bts(a, a.params, b) } -func (a PropertyState) FuncDeclaration(name string, args []string) Fsm { - panic("Illegal call `FuncDeclaration` on PropertyState") +func (a PropertyState) Func(name string, args []string, invoke string) Fsm { + panic("Illegal call `Func` on PropertyState") } func (a PropertyState) Property(name string) Fsm { diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index b7129276ce..90f5330193 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -14,7 +14,7 @@ type Fsm interface { TrueBranch() Fsm FalseBranch() Fsm Bytes(b []byte) Fsm - FuncDeclaration(name string, args []string) Fsm + Func(name string, args []string, invokeParam string) Fsm Property(name string) Fsm } @@ -45,7 +45,7 @@ type params struct { // Unique id for func params. u *uniqid // Predefined variables. - predef predef + predef *predef } func long(f Fsm, params params, value int64) Fsm { @@ -79,6 +79,13 @@ func constant(a Fsm, params params, rideType rideType) Fsm { return a } +func putConstant(params params, rideType rideType) uint16 { + pos := params.b.len() + index := params.c.put(rideType) + params.b.push(index) + return pos +} + func reference(f Fsm, params params, name string) Fsm { pos, ok := params.r.get(name) if !ok { @@ -88,10 +95,7 @@ func reference(f Fsm, params params, name string) Fsm { params.b.write(encode(0)) return f } - //index := params.c.put(rideString(name)) - //params.b.fillContext(index) panic(fmt.Sprintf("reference %s not found", name)) - //return f } params.b.jump(pos) return f diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index 5c0d2797a5..f1d02c6d20 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -9,7 +9,7 @@ func tx(env RideEnvironment, _ ...rideType) (rideType, error) { return env.transaction(), nil } -func mergeWithPredefined(f func(id int) rideFunction, p predef) func(id int) rideFunction { +func mergeWithPredefined(f func(id int) rideFunction, p *predef) func(id int) rideFunction { return func(id int) rideFunction { if c := p.getn(id); c != nil { return c @@ -18,8 +18,22 @@ func mergeWithPredefined(f func(id int) rideFunction, p predef) func(id int) rid } } -var predefined predef = map[string]predefFunc{ +func this(env RideEnvironment, _ ...rideType) (rideType, error) { + return env.this(), nil +} + +var predefinedFunctions = map[string]predefFunc{ "tx": {id: math.MaxUint16 - 0, f: tx}, "unit": {id: math.MaxUint16 - 1, f: unit}, "NOALG": {id: math.MaxUint16 - 2, f: createNoAlg}, + "this": {id: math.MaxUint16 - 3, f: this}, +} + +var predefined *predef + +func init() { + predefined = newPredef(nil) + for k, v := range predefinedFunctions { + predefined.set(k, v.id, v.f) + } } diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 8112b46e5f..00d2a53265 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -5,7 +5,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/proto" ) -func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { +func CallVerifier2(env RideEnvironment, tree *Tree) (RideResult, error) { e, err := treeVerifierEvaluator(env, tree) if err != nil { return nil, errors.Wrap(err, "failed to call verifier") @@ -13,6 +13,14 @@ func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { return e.evaluate() } +func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { + compiled, err := CompileSimpleScript(tree) + if err != nil { + return nil, errors.Wrap(err, "call compile script") + } + return compiled.Run(env) +} + func CallFunction(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { if name == "" { name = "default" diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index 1dc496d87f..31aabc59fa 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -413,6 +413,7 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { } func treeVerifierEvaluator(env RideEnvironment, tree *Tree) (*treeEvaluator, error) { + s, err := newEvaluationScope(tree.LibVersion, env) if err != nil { return nil, errors.Wrap(err, "failed to create scope") diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 7ee0ca6f23..ed2b39eeb3 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -7,63 +7,6 @@ import ( "github.com/pkg/errors" ) -//type Context interface { -// add(name string, rideType2 rideType) Context -// get(name string) (rideType, bool) -//} -//type ContextImpl struct { -// m *im.Map -//} -// -//func newContext() Context { -// return ContextImpl{m: im.New()} -//} -// -//func (a ContextImpl) add(name string, value rideType) Context { -// return ContextImpl{ -// m: a.m.Insert([]byte(name), value), -// } -//} -// -//func (a ContextImpl) get(name string) (rideType, bool) { -// v, ok := a.m.Get([]byte(name)) -// if !ok { -// return nil, ok -// } -// return v.(rideType), ok -//} - -type frame struct { - function bool - back int - context []int - future []int -} - -func newExpressionFrame(pos int) frame { - return frame{ - back: pos, - } -} - -func newFrameContext(pos int, context args, future args) frame { - return frame{ - back: pos, - context: context, - future: future, - } -} - -//func newFunctionFrame(pos int, args []int) frame { -// return frame{ -// function: true, -// back: pos, -// args: args, -// } -//} - -type args = []int - type vm struct { env RideEnvironment code []byte @@ -73,16 +16,23 @@ type vm struct { globals func(int) rideConstructor stack []rideType functionName func(int) string - jpms []int + jmps []int mem map[uint16]uint16 } func (m *vm) run() (RideResult, error) { + numOperations := 0 + limitOperations := 10000 if m.stack != nil { m.stack = m.stack[0:0] } m.mem = make(map[uint16]uint16) for m.ip < len(m.code) { + if numOperations >= limitOperations { + return nil, errors.New("limit operations exceed") + } + numOperations++ + op := m.code[m.ip] m.ip++ switch op { @@ -99,7 +49,7 @@ func (m *vm) run() (RideResult, error) { m.push(rideBoolean(false)) case OpJump: pos := m.arg16() - m.jpms = append(m.jpms, m.ip) + m.jmps = append(m.jmps, m.ip) m.ip = pos case OpJumpIfFalse: pos := m.arg16() @@ -131,7 +81,7 @@ func (m *vm) run() (RideResult, error) { m.push(v) case OpCall: pos := m.arg16() - m.jpms = append(m.jpms, m.ip) + m.jmps = append(m.jmps, m.ip) m.ip = pos case OpExternalCall: @@ -156,7 +106,7 @@ func (m *vm) run() (RideResult, error) { } m.push(res) case OpReturn: - l := len(m.jpms) + l := len(m.jmps) if l == 0 { if len(m.stack) > 0 { v, err := m.pop() @@ -172,7 +122,7 @@ func (m *vm) run() (RideResult, error) { } return nil, errors.New("no result after script execution") } - m.ip, m.jpms = m.jpms[l-1], m.jpms[:l-1] + m.ip, m.jmps = m.jmps[l-1], m.jmps[:l-1] case OpSetArg: id := m.arg16() @@ -181,8 +131,12 @@ func (m *vm) run() (RideResult, error) { case OpUseArg: argid := m.arg16() - m.jpms = append(m.jpms, m.ip) - m.ip = int(m.mem[uint16(argid)]) + m.jmps = append(m.jmps, m.ip) + value, ok := m.mem[uint16(argid)] + if !ok { + return nil, errors.Errorf("no value at argument %d, last jump from %d", argid, m.jmps[len(m.jmps)-1]) + } + m.ip = int(value) default: return nil, errors.Errorf("unknown code %#x", op) diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index 96f44e7df8..b591e5f104 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -9,6 +9,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/ride" "github.com/wavesplatform/gowaves/pkg/settings" "github.com/wavesplatform/gowaves/pkg/types" + "go.uber.org/zap" ) type scriptCaller struct { @@ -103,6 +104,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } + zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) r, err := ride.CallVerifier(env, tree) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 49b382208f..da1baa0c9d 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -8,6 +8,7 @@ import ( "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/ride" + "go.uber.org/zap" ) const ( @@ -18,6 +19,7 @@ const ( ) func scriptBytesToTree(script proto.Script) (*ride.Tree, error) { + zap.S().Error("script: ", script) tree, err := ride.Parse(script) if err != nil { return nil, err diff --git a/pkg/state/transaction_checker.go b/pkg/state/transaction_checker.go index 5ee0c51b4e..081cc99bdd 100644 --- a/pkg/state/transaction_checker.go +++ b/pkg/state/transaction_checker.go @@ -979,7 +979,7 @@ func (tc *transactionChecker) checkSetScriptWithProofs(transaction proto.Transac return nil, err } if len(tx.Script) == 0 { - // No script checks / actions are needed. + // No script checks/actions are needed. if err := tc.stor.scriptsComplexity.saveComplexitiesForAddr(addr, nil, info.blockID); err != nil { return nil, err } From 03e9286e6f46a63a3e51378572a6a57099b837ac Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 12 Nov 2020 20:16:07 +0300 Subject: [PATCH 11/55] Cells for variables. --- go.mod | 2 +- pkg/ride/compiler2.go | 18 +-- pkg/ride/compiler2_test.go | 189 ++++++++++++++++++------------- pkg/ride/compiler_assigment.go | 6 +- pkg/ride/compiler_call_system.go | 3 +- pkg/ride/compiler_call_user.go | 42 +++---- pkg/ride/compiler_func.go | 15 +-- pkg/ride/compiler_helpers.go | 42 +++---- pkg/ride/compiler_main.go | 2 +- pkg/ride/compiler_property.go | 2 +- pkg/ride/compiler_state.go | 48 ++++---- pkg/ride/executable.go | 2 + pkg/ride/opcodes.go | 4 +- pkg/ride/vm.go | 54 ++++++--- 14 files changed, 235 insertions(+), 194 deletions(-) diff --git a/go.mod b/go.mod index 04e4f148ed..74cc4d04ca 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 - github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b + github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b // indirect github.com/fxamacker/cbor/v2 v2.2.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 9e46687705..63bfaf7c57 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -75,19 +75,21 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { if err != nil { return nil, err } + u := &uniqid{} b := newBuilder() - c := newConstants() r := newReferences(nil) - u := &uniqid{} + c := newCell() params := params{ - b: b, - c: c, - r: r, - f: fCheck, - u: u, - predef: predefined, + b: b, + r: r, + f: fCheck, + u: u, + c: c, } + //mergeWithPredefined() + + params.addPredefined("tx", 65535, tx) f := NewMain(params) f, err = ccc(f, node) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 784ae12602..cba7b7b72b 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -72,38 +72,38 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - //{`V1: true`, "AQa3b8tH", nil, true}, - //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, - //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, - //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, - //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, - //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, - //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, - //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - //{`false`, `AQfeYll6`, nil, false}, - //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, - //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, + {`V1: true`, "AQa3b8tH", nil, true}, + {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, + {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + {`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", env, false}, + {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, + {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, + {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, + {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, + {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + {`false`, `AQfeYll6`, nil, false}, + {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, + {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, // Global variables - //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, + {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, - //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, - {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, + {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, //{`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}, @@ -128,42 +128,6 @@ func Test22(t *testing.T) { } } -/* - -let x = 1; let y = 2; func gt(i: Int, i2: Int) = i > i2; gt(x, y) - -*/ -func Test33(t *testing.T) { - - code, entryPoint := buildCode( - at(1), OpPush, 0, 0, OpReturn, - at(2), OpPush, 0, 1, OpReturn, - // - at(3), - OpUseArg, 0, 0, - OpUseArg, 0, 1, - OpExternalCall, 0, 12, 0, 2, - OpReturn, - // ENTRYPOINT - at(0), - OpSetArg, to(1), // jump to the beginning, first variable - OpSetArg, to(2), // jump to the second variable - OpCall, 0, 8, // вызов пользовательской функции add - OpReturn, - ) - - e := Executable{ - LibVersion: 3, - ByteCode: code, - Constants: []rideType{rideInt(2), rideInt(1)}, - EntryPoints: map[string]uint16{"": entryPoint}, - } - - rs, err := e.Run(nil) - t.Log(rs) - t.Log(err) -} - func buildCode(i ...interface{}) ([]byte, uint16) { marks := make(map[int]uint16) b := new(bytes.Buffer) @@ -260,17 +224,17 @@ func TestDoubleCall(t *testing.T) { require.Equal(t, []byte{ - OpPush, 0, 0, + OpRef, 0, 1, OpReturn, OpCall, 0, 0, - OpPush, 0, 1, + OpRef, 0, 3, OpExternalCall, 0, 3, 0, 2, OpReturn, }, f.ByteCode) - require.EqualValues(t, 5, f.EntryPoints[""]) + require.EqualValues(t, 4, f.EntryPoints[""]) rs, err := f.Run(nil) require.NoError(t, err) @@ -297,27 +261,90 @@ func TestCallWithConstArg(t *testing.T) { f, err := compileSimpleScript(3, n) require.NoError(t, err) - require.Equal(t, - []byte{ - OpUseArg, 0, 1, OpReturn, // arguments section - OpJump, 0, 0, // Function execution code. One line: reference to `v` argument. - OpReturn, + bt := []byte{ + //OpUseArg, 0, 1, OpReturn, // arguments section + OpRef, 0, 1, // Function execution code. One line: reference to `v` argument. + OpReturn, - OpTrue, OpReturn, // define constant + // call function + OpSetArg, 0, 2, 0, 1, + OpCall, 0, 0, + + OpReturn, + } - // call function - OpSetArg, 0, 1, 0, 9, - OpCall, 0, 4, + require.Equal(t, bt, f.ByteCode) - OpReturn, - }, - f.ByteCode) + f.ByteCode = bt + f.EntryPoints[""] = 4 rs, err := f.Run(nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } +// func id(v: Boolean) = v && v; id(true) +func TestMultipleCallConstantFuncArgument(t *testing.T) { + source := `BAoBAAAAAmlkAAAAAQAAAAF2AwUAAAABdgUAAAABdgcJAQAAAAJpZAAAAAEG3g2xRQ==` + + state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }} + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileSimpleScript(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + res, err := script.Run(env) + require.NoError(t, err) + assert.NotNil(t, res) + r, ok := res.(ScriptResult) + assert.True(t, ok) + assert.Equal(t, true, r.Result()) + + //f, err := compileSimpleScript(3, n) + //require.NoError(t, err) + + //require.Equal(t, + // []byte{ + // OpUseArg, 0, 1, OpReturn, // arguments section + // OpJump, 0, 0, // Function execution code. One line: reference to `v` argument. + // OpReturn, + // + // OpTrue, OpReturn, // define constant + // + // // call function + // OpSetArg, 0, 1, 0, 9, + // OpCall, 0, 4, + // + // OpReturn, + // }, + // f.ByteCode) + // + //rs, err := f.Run(nil) + //require.NoError(t, err) + //require.Equal(t, true, rs.Result()) +} + /* {-# STDLIB_VERSION 3 #-} diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 824eee47fd..b1720c2f95 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -17,7 +17,7 @@ func (a AssigmentState) Func(name string, args []string, invoke string) Fsm { } func (a AssigmentState) Bytes(b []byte) Fsm { - return constant(a, a.params, rideBytes(b)) + return bts(a, a.params, b) } func (a AssigmentState) Condition() Fsm { @@ -63,7 +63,9 @@ func (a AssigmentState) Assigment(name string) Fsm { func (a AssigmentState) Return() Fsm { a.b.ret() // store reference on variable and it's offset. - a.r.set(a.name, a.offset) + n := a.u.next() + a.c.set(n, nil, nil, a.offset) + a.r.set(a.name, n) return a.prev } diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index d661fea43f..353039d668 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -65,8 +65,7 @@ func (a CallSystemState) Assigment(name string) Fsm { } func (a CallSystemState) Long(value int64) Fsm { - index := a.params.c.put(rideInt(value)) - a.params.b.push(index) + a.b.push(a.constant(rideInt(value))) return a } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index c3b9481e9d..ed846946b4 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -9,7 +9,16 @@ type CallUserState struct { name string argc uint16 // positions of arguments - argn []uint16 + argn []uniqueid +} + +func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { + return &CallUserState{ + prev: prev, + params: params, + name: name, + argc: argc, + } } func (a CallUserState) Property(name string) Fsm { @@ -22,7 +31,6 @@ func (a CallUserState) Func(name string, args []string, invoke string) Fsm { func (a CallUserState) Bytes(b []byte) Fsm { a.argn = append(a.argn, putConstant(a.params, rideBytes(b))) - a.b.ret() return a } @@ -40,38 +48,20 @@ func (a CallUserState) FalseBranch() Fsm { func (a CallUserState) String(s string) Fsm { a.argn = append(a.argn, putConstant(a.params, rideString(s))) - a.b.ret() return a } func (a CallUserState) Boolean(v bool) Fsm { - pos := a.b.len() - a.b.writeByte(OpTrue) - a.argn = append(a.argn, pos) - a.b.ret() + a.argn = append(a.argn, putConstant(a.params, rideBoolean(v))) return a } -//func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { -// return newCallFsm(prev, params, name, argc) -//} - -func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { - return &CallUserState{ - prev: prev, - params: params, - name: name, - argc: argc, - } -} - func (a CallUserState) Assigment(name string) Fsm { return assigmentFsmTransition(a, a.params, name) } func (a CallUserState) Long(value int64) Fsm { a.argn = append(a.argn, putConstant(a.params, rideInt(value))) - a.b.ret() return a } @@ -81,15 +71,14 @@ func (a CallUserState) Return() Fsm { if !ok { panic(fmt.Sprintf("user function `%s` not found", a.name)) } - a.b.startPos() for i, pos := range a.argn { a.b.writeByte(OpSetArg) - uniqid, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i)) + funcParamID, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i)) if !ok { panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) } - a.b.write(encode(uniqid)) a.b.write(encode(pos)) + a.b.write(encode(funcParamID)) } a.b.call(n, a.argc) @@ -101,5 +90,10 @@ func (a CallUserState) Call(name string, argc uint16) Fsm { } func (a CallUserState) Reference(name string) Fsm { + rs, ok := a.r.get(name) + if !ok { + panic("CallUserState Reference " + name + " not found") + } + a.argn = append(a.argn, rs) return reference(a, a.params, name) } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 63dcec0bbc..6dc8553c43 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -37,17 +37,15 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP // avoid corrupting parent state. params.r = newReferences(params.r) for i := range args { - params.r.set(args[i], params.b.len()) + e := params.u.next() + params.r.set(args[i], e) // set to global - globalScope.set(fmt.Sprintf("%s$%d", name, i), params.u.next()) - params.b.w.WriteByte(OpUseArg) - params.b.w.Write(encode(params.u.cur())) - params.b.w.WriteByte(OpReturn) + globalScope.set(fmt.Sprintf("%s$%d", name, i), e) } // assume that it's verifier if invokeParam != "" { // tx - params.predef = newPredefWithValue(params.predef, "tx", math.MaxUint16, tx) + //params.predef = newPredefWithValue(params.predef, "tx", math.MaxUint16, tx) pos := params.b.len() params.b.writeByte(OpExternalCall) params.b.write(encode(math.MaxUint16)) @@ -74,12 +72,10 @@ func (a FuncState) Assigment(name string) Fsm { func (a FuncState) Return() Fsm { a.globalScope.set(a.name, a.offset) // TODO clean args - //a.b.writeByte(OpPopCtx) a.b.ret() // if function has invoke param, it means no other code will be provided. if a.invokeParam != "" { - a.b.startPos() a.b.writeByte(OpCall) a.b.write(encode(a.offset)) } @@ -88,8 +84,7 @@ func (a FuncState) Return() Fsm { } func (a FuncState) Long(value int64) Fsm { - index := a.params.c.put(rideInt(value)) - a.params.b.push(index) + a.params.b.push(a.constant(rideInt(value))) return a } diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 619eafdcec..f3bac355df 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -24,7 +24,7 @@ func (b *builder) writeStub(len int) (position uint16) { } func (b *builder) push(uint162 uint16) { - b.w.WriteByte(OpPush) + b.w.WriteByte(OpRef) b.w.Write(encode(uint162)) } @@ -45,7 +45,7 @@ func (b *builder) ret() { } func (b *builder) jump(uint162 uint16) { - b.w.WriteByte(OpJump) + b.w.WriteByte(OpRef) b.w.Write(encode(uint162)) } @@ -92,28 +92,32 @@ func (b *builder) write(i []byte) { b.w.Write(i) } -//func (b *builder) fillContext(id constid) { -// b.w.WriteByte(OpFillContext) -// b.w.Write(encode(id)) -//} - -type constants struct { - values []rideType +type point struct { + position uint16 + value rideType + fn rideFunction } -func newConstants() *constants { - return &constants{} +type cell struct { + values map[uniqueid]point } -func (a *constants) put(value rideType) uint16 { - a.values = append(a.values, value) - return uint16(len(a.values) - 1) +func newCell() *cell { + return &cell{ + values: make(map[uniqueid]point), + } } -func (a *constants) constants() []rideType { - return a.values +func (a *cell) set(u uniqueid, result rideType, fn rideFunction, position uint16) { + a.values[u] = point{ + position: position, + value: result, + fn: fn, + } } +type uniqueid = uint16 + type references struct { prev *references refs map[string]uint16 @@ -126,7 +130,7 @@ func newReferences(prev *references) *references { } } -func (a *references) get(name string) (uint16, bool) { +func (a *references) get(name string) (uniqueid, bool) { if a == nil { return 0, false } @@ -136,8 +140,8 @@ func (a *references) get(name string) (uint16, bool) { return a.prev.get(name) } -func (a *references) set(name string, offset uint16) { - a.refs[name] = offset +func (a *references) set(name string, uniq uniqueid) { + a.refs[name] = uniq } type predefFunc struct { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 8fc7979b8d..7df3383884 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -77,7 +77,7 @@ func (a MainState) BuildExecutable(version int) *Executable { return &Executable{ LibVersion: version, ByteCode: code, - Constants: a.c.constants(), + References: a.c.values, EntryPoints: map[string]uint16{"": startAt}, } } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index fd3b4ba28d..365e4b92a7 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -20,7 +20,7 @@ func (a PropertyState) Assigment(name string) Fsm { func (a PropertyState) Return() Fsm { a.b.writeByte(OpProperty) - index := a.params.c.put(rideString(a.name)) + index := a.constant(rideString(a.name)) a.params.b.write(encode(index)) return a.prev } diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 90f5330193..556add21e7 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -36,8 +36,6 @@ type FunctionChecker func(string) (uint16, bool) type params struct { // Wrapper on bytes.Buffer with handy methods. b *builder - // Slice of constants. - c *constants // Relation of variables and it's offset. r *references // Way to get function id. @@ -45,58 +43,56 @@ type params struct { // Unique id for func params. u *uniqid // Predefined variables. - predef *predef + c *cell +} + +func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) { + a.r.set(name, id) + a.c.set(id, nil, fn, 0) +} + +func (a *params) constant(value rideType) uniqueid { + n := a.u.next() + a.c.set(n, value, nil, 0) + return n } func long(f Fsm, params params, value int64) Fsm { - index := params.c.put(rideInt(value)) - params.b.push(index) - params.b.ret() + params.b.push(params.constant(rideInt(value))) return f } func boolean(f Fsm, params params, value bool) Fsm { - params.b.bool(value) + params.b.push(params.constant(rideBoolean(value))) return f } func bts(f Fsm, params params, value []byte) Fsm { - index := params.c.put(rideBytes(value)) - params.b.push(index) + params.b.push(params.constant(rideBytes(value))) return f } -func str(a Fsm, params params, s string) Fsm { - index := params.c.put(rideString(s)) - params.b.push(index) +func str(a Fsm, params params, value string) Fsm { + params.b.push(params.constant(rideString(value))) return a } -// TODO: remove duplicate -func constant(a Fsm, params params, rideType rideType) Fsm { - index := params.c.put(rideType) - params.b.push(index) +func constant(a Fsm, params params, value rideType) Fsm { + params.b.push(params.constant(value)) return a } func putConstant(params params, rideType rideType) uint16 { - pos := params.b.len() - index := params.c.put(rideType) - params.b.push(index) - return pos + index := params.constant(rideType) + return index } func reference(f Fsm, params params, name string) Fsm { pos, ok := params.r.get(name) if !ok { - if n, ok := params.predef.get(name); ok { - params.b.writeByte(OpExternalCall) - params.b.write(encode(n.id)) - params.b.write(encode(0)) - return f - } panic(fmt.Sprintf("reference %s not found", name)) } + //params.b params.b.jump(pos) return f } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index e692d8aeaf..6bf12fc06a 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -5,6 +5,7 @@ type Executable struct { ByteCode []byte Constants []rideType EntryPoints map[string]uint16 + References map[uniqueid]point } func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { @@ -25,6 +26,7 @@ func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { functions: mergeWithPredefined(fSelect, predefined), functionName: provider, env: environment, + ref: a.References, } //v.push(environment.transaction()) diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index b00abf7446..acd8fe385b 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -15,8 +15,10 @@ const ( OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. - OpSetArg //11 0xb - Set value into cell. Two parameters: constant id and cell id. + OpSetArg //11 0xb - FROM (global) -> TO (local): Set value into cell. Two parameters: constant id and cell id. OpUseArg //12 0xc - Use stored value in cell. One param: cell id. + OpCache //13 0xd - Put constant on stack. One parameter: constant ID. + OpRef //14 0xe = ref id // odd, will be removed. OpGlobal diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index ed2b39eeb3..524ded6328 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -17,7 +17,8 @@ type vm struct { stack []rideType functionName func(int) string jmps []int - mem map[uint16]uint16 + cache map[int]rideType + ref map[uint16]point } func (m *vm) run() (RideResult, error) { @@ -26,7 +27,7 @@ func (m *vm) run() (RideResult, error) { if m.stack != nil { m.stack = m.stack[0:0] } - m.mem = make(map[uint16]uint16) + for m.ip < len(m.code) { if numOperations >= limitOperations { return nil, errors.New("limit operations exceed") @@ -43,14 +44,14 @@ func (m *vm) run() (RideResult, error) { if err != nil { return nil, errors.Wrap(err, "failed to pop value") } - case OpTrue: - m.push(rideBoolean(true)) - case OpFalse: - m.push(rideBoolean(false)) case OpJump: pos := m.arg16() - m.jmps = append(m.jmps, m.ip) - m.ip = pos + if rs, ok := m.cache[pos]; ok { + m.push(rs) + } else { + m.jmps = append(m.jmps, m.ip) + m.ip = pos + } case OpJumpIfFalse: pos := m.arg16() val, err := m.pop() @@ -69,7 +70,7 @@ func (m *vm) run() (RideResult, error) { if err != nil { return nil, errors.Wrap(err, "failed to get object") } - prop := m.constant() + prop := m.ref[m.uint16()].value p, ok := prop.(rideString) if !ok { return nil, errors.Errorf("invalid property name type '%s'", prop.instanceOf()) @@ -125,18 +126,28 @@ func (m *vm) run() (RideResult, error) { m.ip, m.jmps = m.jmps[l-1], m.jmps[:l-1] case OpSetArg: - id := m.arg16() - value := m.arg16() - m.mem[uint16(id)] = uint16(value) + from := m.uint16() + to := m.uint16() + m.ref[to] = m.ref[from] - case OpUseArg: - argid := m.arg16() - m.jmps = append(m.jmps, m.ip) - value, ok := m.mem[uint16(argid)] + case OpRef: + refID := m.uint16() + point, ok := m.ref[refID] if !ok { - return nil, errors.Errorf("no value at argument %d, last jump from %d", argid, m.jmps[len(m.jmps)-1]) + return nil, errors.Errorf("reference %d not found", refID) + } + if point.value != nil { + m.push(point.value) + } else if point.fn != nil { + rs, err := point.fn(m.env) + if err != nil { + return nil, err + } + m.push(rs) + } else { + m.jmps = append(m.jmps, m.ip) + m.ip = int(point.position) } - m.ip = int(value) default: return nil, errors.Errorf("unknown code %#x", op) @@ -170,6 +181,13 @@ func (m *vm) arg16() int { return int(res) } +func (m *vm) uint16() uint16 { + //TODO: add check + res := binary.BigEndian.Uint16(m.code[m.ip : m.ip+2]) + m.ip += 2 + return res +} + func (m *vm) constant() rideType { //TODO: add check return m.constants[m.arg16()] From 31653345b3d39c089dfbef7572a021f2c51b5541 Mon Sep 17 00:00:00 2001 From: Frozen Date: Mon, 23 Nov 2020 19:06:48 +0300 Subject: [PATCH 12/55] Fix bug with if stmt. --- pkg/proto/scripting.go | 18 +++ pkg/ride/compiler2.go | 7 +- pkg/ride/compiler2_test.go | 262 ++++++++++++++++++++++--------- pkg/ride/compiler_assigment.go | 8 +- pkg/ride/compiler_call_system.go | 43 ++--- pkg/ride/compiler_call_user.go | 13 +- pkg/ride/compiler_conditional.go | 55 ++++++- pkg/ride/compiler_func.go | 59 ++++--- pkg/ride/compiler_helpers.go | 5 + pkg/ride/compiler_main.go | 6 + pkg/ride/compiler_property.go | 4 + pkg/ride/compiler_state.go | 1 + pkg/ride/decompiler.go | 118 ++++++++++++++ pkg/ride/result.go | 37 ++++- pkg/ride/result_test.go | 11 ++ pkg/ride/tree_evaluation.go | 19 ++- pkg/ride/tree_evaluator.go | 7 +- pkg/ride/vm.go | 17 +- pkg/state/script_caller.go | 22 ++- 19 files changed, 550 insertions(+), 162 deletions(-) create mode 100644 pkg/ride/decompiler.go create mode 100644 pkg/ride/result_test.go diff --git a/pkg/proto/scripting.go b/pkg/proto/scripting.go index fd715b4d7f..ba7b7ff66c 100644 --- a/pkg/proto/scripting.go +++ b/pkg/proto/scripting.go @@ -2,6 +2,7 @@ package proto import ( "encoding/binary" + "fmt" "unicode/utf16" "github.com/pkg/errors" @@ -10,6 +11,23 @@ import ( g "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves" ) +type ScriptActions []ScriptAction + +func (a ScriptActions) Eq(b ScriptActions) bool { + if len(a) != len(b) { + return false + } + + for i := range a { + left := fmt.Sprintf("%+v", a[i]) + right := fmt.Sprintf("%+v", b[i]) + if left != right { + return false + } + } + return true +} + // ScriptAction common interface of script invocation actions. type ScriptAction interface { scriptAction() diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 63bfaf7c57..f59d99ee42 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -79,6 +79,7 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { b := newBuilder() r := newReferences(nil) c := newCell() + b.writeByte(OpReturn) params := params{ b: b, @@ -87,9 +88,9 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { u: u, c: c, } - //mergeWithPredefined() - - params.addPredefined("tx", 65535, tx) + for k, v := range predefinedFunctions { + params.addPredefined(k, v.id, v.f) + } f := NewMain(params) f, err = ccc(f, node) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index cba7b7b72b..ab88fe08c3 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -3,8 +3,7 @@ package ride import ( "bytes" "encoding/base64" - "fmt" - "strings" + "errors" "testing" "github.com/stretchr/testify/assert" @@ -54,9 +53,15 @@ func Test_ccc(t *testing.T) { } func Test22(t *testing.T) { - state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }} + 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") + }, + } env := &MockRideEnvironment{ transactionFunc: testTransferObject, stateFunc: func() types.SmartState { @@ -65,6 +70,9 @@ func Test22(t *testing.T) { schemeFunc: func() byte { return 'T' }, + thisFunc: func() rideType { + return rideAddress{} + }, } for _, test := range []struct { comment string @@ -81,9 +89,11 @@ func Test22(t *testing.T) { {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, @@ -97,12 +107,12 @@ func Test22(t *testing.T) { {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, // Global variables {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, - {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, //{`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}, @@ -197,6 +207,43 @@ func TestCallExternal(t *testing.T) { f.ByteCode) } +// let x = if (true) then true else false; x +func TestIfConditionRightByteCode(t *testing.T) { + n := &AssignmentNode{ + Name: "x", + Expression: &ConditionalNode{ + Condition: &BooleanNode{Value: true}, + TrueExpression: &BooleanNode{Value: true}, + FalseExpression: &BooleanNode{Value: false}, + }, + Block: &ReferenceNode{ + Name: "x", + }, + } + + f, err := compileSimpleScript(3, n) + require.NoError(t, err) + + require.Equal(t, + []byte{ + OpReturn, + OpRef, 0, 1, + OpJumpIfFalse, 0, 11, 0, 15, 0, 19, + OpRef, 0, 2, + OpReturn, + OpRef, 0, 3, + OpReturn, + OpReturn, + OpRef, 0, 4, + OpReturn, + }, + f.ByteCode) + + rs, err := f.Run(nil) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) +} + //func a() = 1; a() == 1 func TestDoubleCall(t *testing.T) { n := &FunctionDeclarationNode{ @@ -442,9 +489,14 @@ base64:AwoBAAAAAWYAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBwAAAACBQAAAAR0aGlzBQAAAANrZ func Test2121(t *testing.T) { source := `AwoBAAAAAWYAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBwAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAWEFAAAAByRtYXRjaDAAAAAAAAAAAAEAAAAAAAAAAAAEAAAAAWEJAQAAAAFmAAAAAQIAAAABYQQAAAABYgkBAAAAAWYAAAABAgAAAAFiBAAAAAFjCQEAAAABZgAAAAECAAAAAWMEAAAAAWQJAQAAAAFmAAAAAQIAAAABZAQAAAABZQkBAAAAAWYAAAABAgAAAAFlAwkAAAAAAAACCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIFAAAAAWEFAAAAAWIFAAAAAWMFAAAAAWQFAAAAAWUAAAAAAAAAAAUJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V5B4xspLY=` - state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }} + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return &proto.BinaryDataEntry{}, nil + }, + } env := &MockRideEnvironment{ transactionFunc: testTransferObject, stateFunc: func() types.SmartState { @@ -457,7 +509,12 @@ func Test2121(t *testing.T) { return true }, thisFunc: func() rideType { - return testTransferObject() + addr, err := proto.NewAddressFromString("3MfnF2zbXiM89zxcenPVT9fa4qfVJqeCZzj") + if err != nil { + panic(err) + } + + return rideAddress(addr) }, } @@ -468,7 +525,7 @@ func Test2121(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - t.Log(detree(tree.Verifier)) + t.Log(Decompiler(tree.Verifier)) script, err := CompileSimpleScript(tree) require.NoError(t, err) @@ -482,67 +539,122 @@ func Test2121(t *testing.T) { assert.Equal(t, true, r.Result()) } -func detree(tree Node) string { - s := &strings.Builder{} - detree_(s, tree, 0) - return s.String() +/* +{-# 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 + } } -func detree_(s *strings.Builder, tree Node, shift int) { - switch n := tree.(type) { - case *FunctionDeclarationNode: - s.WriteString(fmt.Sprintf("func %s(", n.Name)) - for _, a := range n.Arguments { - s.WriteString(a) - s.WriteString(",") - } - s.WriteString(") {\n") - s.WriteString(strings.Repeat(" ", shift+1)) - detree_(s, n.Body, shift+1) - s.WriteString("}\n") - detree_(s, n.Block, shift) - - case *AssignmentNode: - s.WriteString(fmt.Sprintf("let %s = ", n.Name)) - detree_(s, n.Expression, shift) - s.WriteString("\n") - detree_(s, n.Block, shift) - - case *ConditionalNode: - s.WriteString(strings.Repeat(" ", shift*4)) - s.WriteString(fmt.Sprintf("if (")) - detree_(s, n.Condition, shift) - s.WriteString(") {\n") - s.WriteString(strings.Repeat(" ", (shift+1)*4)) - detree_(s, n.TrueExpression, shift+1) - s.WriteString("} else {\n") - s.WriteString(strings.Repeat(" ", (shift+1)*4)) - detree_(s, n.FalseExpression, shift+1) - s.WriteString("}\n") - case *FunctionCallNode: - s.WriteString(n.Name) - s.WriteString("(") - for _, a := range n.Arguments { - detree_(s, a, shift) - s.WriteString(",") - } - s.WriteString(")") - case *ReferenceNode: - s.WriteString(n.Name) - case *StringNode: - s.WriteString(`"`) - s.WriteString(n.Value) - s.WriteString(`"`) - case *PropertyNode: - detree_(s, n.Object, shift) - s.WriteString(".") - s.WriteString(n.Name) - case *BooleanNode: - s.WriteString(fmt.Sprintf("%t", n.Value)) - case *LongNode: - s.WriteString(fmt.Sprintf("%d", n.Value)) - default: - panic(fmt.Sprintf("unknown type %T", n)) +1 == id(true) + +*/ +func TestIfStmt(t *testing.T) { + source := `BAoBAAAAAmlkAAAAAQAAAAF2AwUAAAABdgQAAAABeAkAAAIAAAABAgAAAAFhAAAAAAAAAAABBAAAAAF4CQAAAgAAAAECAAAAAWIAAAAAAAAAAAIJAAAAAAAAAgAAAAAAAAAAAQkBAAAAAmlkAAAAAQYYAiEb` + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileSimpleScript(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + res, err := script.Run(env) + require.NoError(t, err) + assert.NotNil(t, res) + r, ok := res.(ScriptResult) + assert.True(t, ok) + assert.Equal(t, true, r.Result()) +} + +/* + + +let dd = @extrNative(1050)(this,"dd",); +func f(key) { + let $match0 = getBinary(this,key); + if (instanceOf($match0,"ByteVector")) { + let a = $match0; + 2-1 + } else { + 0 } - //return s.String() +} +let a = ((((f("a",) + f("b",)) + f("c",)) + f("d",)) + f("e",)); +let b = ((((f("g",) + f("h",)) + f("i",)) + f("j",)) + f("k",)); +let c = ((((f("a",) + f("b",)) + f("c",)) + f("d",)) + f("k",)); +let d = ((((f("g",) + f("h",)) + f("i",)) + f("j",)) + f("e",)); +let e = ((((f("a",) + f("b",)) + f("c",)) + f("j",)) + f("e",)); +let g = ((f("g",) + f("h",)) + value(f("i",),)); +if ( + if ( + if ( + if ( + if ( + if ( + if ((dd == 1)) { + (a == 5) + } else { + false + } + ) { (b == parseIntValue("0",)) } else { false }) { (c == 4) } else { false }) { (d == parseIntValue("1",)) } else { false }) { (e == 4) } else { false }) { (g == parseIntValue("0",)) } else { false }) { true } else { 500(tx.bodyBytes,401(tx.proofs,0,),tx.senderPublicKey,) } + + + +AwQAAAACZGQJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAABHRoaXMCAAAAAmRkCgEAAAABZgAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEHAAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAKQnl0ZVZlY3RvcgQAAAABYQUAAAAHJG1hdGNoMAkAAGUAAAACAAAAAAAAAAACAAAAAAAAAAABAAAAAAAAAAAABAAAAAFhCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFlBAAAAAFiCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFrBAAAAAFjCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFrBAAAAAFkCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFlCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFnCQAAZAAAAAIJAABkAAAAAgkBAAAAAWYAAAABAgAAAAFnCQEAAAABZgAAAAECAAAAAWgJAQAAAAV2YWx1ZQAAAAEJAQAAAAFmAAAAAQIAAAABaQMDAwMDAwMJAAAAAAAAAgUAAAACZGQAAAAAAAAAAAEJAAAAAAAAAgUAAAABYQAAAAAAAAAABQcJAAAAAAAAAgUAAAABYgkBAAAADXBhcnNlSW50VmFsdWUAAAABAgAAAAEwBwkAAAAAAAACBQAAAAFjAAAAAAAAAAAEBwkAAAAAAAACBQAAAAFkCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAECAAAAATEHCQAAAAAAAAIFAAAAAWUAAAAAAAAAAAQHCQAAAAAAAAIFAAAAAWcJAQAAAA1wYXJzZUludFZhbHVlAAAAAQIAAAABMAcGCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAgFAAAAAnR4AAAAD3NlbmRlclB1YmxpY0tlebYLD8w= + +*/ + +func Test44(t *testing.T) { + source := "AwQAAAACZGQJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAABHRoaXMCAAAAAmRkCgEAAAABZgAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEHAAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAKQnl0ZVZlY3RvcgQAAAABYQUAAAAHJG1hdGNoMAkAAGUAAAACAAAAAAAAAAACAAAAAAAAAAABAAAAAAAAAAAABAAAAAFhCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFlBAAAAAFiCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFrBAAAAAFjCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFrBAAAAAFkCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFlCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFnCQAAZAAAAAIJAABkAAAAAgkBAAAAAWYAAAABAgAAAAFnCQEAAAABZgAAAAECAAAAAWgJAQAAAAV2YWx1ZQAAAAEJAQAAAAFmAAAAAQIAAAABaQMDAwMDAwMJAAAAAAAAAgUAAAACZGQAAAAAAAAAAAEJAAAAAAAAAgUAAAABYQAAAAAAAAAABQcJAAAAAAAAAgUAAAABYgkBAAAADXBhcnNlSW50VmFsdWUAAAABAgAAAAEwBwkAAAAAAAACBQAAAAFjAAAAAAAAAAAEBwkAAAAAAAACBQAAAAFkCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAECAAAAATEHCQAAAAAAAAIFAAAAAWUAAAAAAAAAAAQHCQAAAAAAAAIFAAAAAWcJAQAAAA1wYXJzZUludFZhbHVlAAAAAQIAAAABMAcGCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAgFAAAAAnR4AAAAD3NlbmRlclB1YmxpY0tlebYLD8w=" + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileSimpleScript(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + t.Log(Decompiler(tree.Verifier)) + + //res, err := script.Run(env) + //require.NoError(t, err) + //assert.NotNil(t, res) + //r, ok := res.(ScriptResult) + //assert.True(t, ok) + //assert.Equal(t, true, r.Result()) + } diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index b1720c2f95..af62a3cead 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -6,6 +6,12 @@ type AssigmentState struct { prev Fsm name string offset uint16 + ret uint16 +} + +func (a AssigmentState) retAssigment(pos uint16) Fsm { + a.ret = pos + return a } func (a AssigmentState) Property(name string) Fsm { @@ -66,7 +72,7 @@ func (a AssigmentState) Return() Fsm { n := a.u.next() a.c.set(n, nil, nil, a.offset) a.r.set(a.name, n) - return a.prev + return a.prev.retAssigment(a.params.b.len()) } func (a AssigmentState) Long(value int64) Fsm { diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 353039d668..ab009fd81a 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -10,6 +10,14 @@ type CallSystemState struct { argc uint16 // positions of arguments argn []uint16 + // Position where we started write code for current state. + startedAt uint16 + retAssig uint16 +} + +func (a CallSystemState) retAssigment(pos uint16) Fsm { + a.retAssig = pos + return a } func (a CallSystemState) Property(name string) Fsm { @@ -53,10 +61,11 @@ func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { func newCallSystemFsm(prev Fsm, params params, name string, argc uint16) Fsm { return &CallSystemState{ - prev: prev, - params: params, - name: name, - argc: argc, + prev: prev, + params: params, + name: name, + argc: argc, + startedAt: params.b.len(), } } @@ -70,36 +79,12 @@ func (a CallSystemState) Long(value int64) Fsm { } func (a CallSystemState) Return() Fsm { - - //// check user functions - //n, ok := a.r.get(a.name) - //if ok { - // a.b.startPos() - // for _, pos := range a.argn { - // a.b.writeByte(OpSetArg) - // a.b.write(encode(pos)) - // //a.b.writeByte(OpReturn) - // } - // - // a.b.call(n, a.argc) - // return a.prev - //} - - //a.b.startPos() n, ok := a.f(a.name) if !ok { - //if p, ok := a.predef.get(a.name); ok { - // a.b.externalCall(p.id, a.argc) - // return a.prev - //} panic(fmt.Sprintf("system function named `%s` not found", a.name)) } - //for _, pos := range a.argn { - // a.b.writeByte(OpJump) - // a.b.write(encode(pos)) - //} a.b.externalCall(n, a.argc) - return a.prev + return a.prev.retAssigment(a.startedAt) } func (a CallSystemState) Call(name string, argc uint16) Fsm { diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index ed846946b4..95dd90305e 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -12,6 +12,10 @@ type CallUserState struct { argn []uniqueid } +func (a CallUserState) retAssigment(pos uint16) Fsm { + panic("implement me") +} + func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { return &CallUserState{ prev: prev, @@ -81,7 +85,12 @@ func (a CallUserState) Return() Fsm { a.b.write(encode(funcParamID)) } - a.b.call(n, a.argc) + point, ok := a.params.c.get(n) + if !ok { + panic(fmt.Sprintf("no point %d found in cell", n)) + } + + a.b.call(point.position, a.argc) return a.prev } @@ -95,5 +104,5 @@ func (a CallUserState) Reference(name string) Fsm { panic("CallUserState Reference " + name + " not found") } a.argn = append(a.argn, rs) - return reference(a, a.params, name) + return a } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 40cec2360c..249e4e5afb 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -3,8 +3,36 @@ package ride // If-else statement. type ConditionalState struct { params - prev Fsm - patchPosition uint16 + prev Fsm + /* + Offset where true branch starts execution. + We need this because code can look like: + if (true) then { + let x = throw() + 5 + } else { + let y = throw() + 6 + } + + `X` and `y` should not be executed. + + */ + patchTruePosition uint16 + // Same as true position. + patchFalsePosition uint16 + // Offset where `if` code block ends. + patchNextPosition uint16 + retAssig uint16 + startedAt uint16 + trueStartedAt uint16 + falseStartedAt uint16 + rets []uint16 +} + +func (a ConditionalState) retAssigment(pos uint16) Fsm { + a.retAssig = pos + return a } func (a ConditionalState) Property(name string) Fsm { @@ -16,29 +44,33 @@ func (a ConditionalState) Func(name string, args []string, invoke string) Fsm { } func (a ConditionalState) Bytes(b []byte) Fsm { + a.rets = append(a.rets, a.params.b.len()) return constant(a, a.params, rideBytes(b)) } func conditionalTransition(prev Fsm, params params) Fsm { return ConditionalState{ - prev: prev, - params: params, + prev: prev, + params: params, + startedAt: params.b.len(), } } func (a ConditionalState) Condition() Fsm { + a.rets = append(a.rets, a.params.b.len()) return conditionalTransition(a, a.params) } func (a ConditionalState) TrueBranch() Fsm { a.b.jpmIfFalse() - a.patchPosition = a.b.writeStub(2) + a.patchTruePosition = a.b.writeStub(2) + a.patchFalsePosition = a.b.writeStub(2) + a.patchNextPosition = a.b.writeStub(2) return a } func (a ConditionalState) FalseBranch() Fsm { a.b.ret() - a.b.patch(a.patchPosition, encode(a.b.len())) return a } @@ -48,25 +80,34 @@ func (a ConditionalState) Assigment(name string) Fsm { func (a ConditionalState) Return() Fsm { a.b.ret() - return a.prev + a.b.patch(a.patchTruePosition, encode(a.rets[1])) + a.b.patch(a.patchFalsePosition, encode(a.rets[2])) + a.b.patch(a.patchNextPosition, encode(a.b.len())) + return a.prev.retAssigment(a.startedAt) } func (a ConditionalState) Long(value int64) Fsm { + a.rets = append(a.rets, a.params.b.len()) return long(a, a.params, value) } func (a ConditionalState) Call(name string, argc uint16) Fsm { + a.rets = append(a.rets, a.params.b.len()) + // TODO check if we need ret here return callTransition(a, a.params, name, argc) } func (a ConditionalState) Reference(name string) Fsm { + a.rets = append(a.rets, a.params.b.len()) return reference(a, a.params, name) } func (a ConditionalState) Boolean(v bool) Fsm { + a.rets = append(a.rets, a.params.b.len()) return boolean(a, a.params, v) } func (a ConditionalState) String(s string) Fsm { + a.rets = append(a.rets, a.params.b.len()) return str(a, a.params, s) } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 6dc8553c43..a0a70eb40b 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -18,12 +18,17 @@ func (a arguments) pos(name string) int { type FuncState struct { params - prev Fsm - name string - args arguments - offset uint16 - globalScope *references - invokeParam string + prev Fsm + name string + args arguments + globalScope *references + invokeParam string + lastStmtOffset uint16 +} + +func (a FuncState) retAssigment(pos uint16) Fsm { + a.lastStmtOffset = pos + return a } func (a FuncState) Property(name string) Fsm { @@ -45,8 +50,10 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP // assume that it's verifier if invokeParam != "" { // tx - //params.predef = newPredefWithValue(params.predef, "tx", math.MaxUint16, tx) - pos := params.b.len() + pos, ok := params.r.get("tx") + if !ok { + panic("no `tx` in function call") + } params.b.writeByte(OpExternalCall) params.b.write(encode(math.MaxUint16)) params.b.write(encode(0)) @@ -55,11 +62,11 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP } return &FuncState{ - prev: prev, - name: name, - args: args, - params: params, - offset: params.b.len(), + prev: prev, + name: name, + args: args, + params: params, + //offset: params.b.len(), globalScope: globalScope, invokeParam: invokeParam, } @@ -70,54 +77,64 @@ func (a FuncState) Assigment(name string) Fsm { } func (a FuncState) Return() Fsm { - a.globalScope.set(a.name, a.offset) + funcID := a.params.u.next() + a.globalScope.set(a.name, funcID) + a.params.c.set(funcID, nil, nil, a.lastStmtOffset) // TODO clean args a.b.ret() // if function has invoke param, it means no other code will be provided. if a.invokeParam != "" { + a.b.startPos() a.b.writeByte(OpCall) - a.b.write(encode(a.offset)) + a.b.write(encode(a.lastStmtOffset)) } - return a.prev + return a.prev.retAssigment(a.b.len()) } func (a FuncState) Long(value int64) Fsm { + a.lastStmtOffset = a.b.len() a.params.b.push(a.constant(rideInt(value))) return a } func (a FuncState) Call(name string, argc uint16) Fsm { + a.lastStmtOffset = a.b.len() return callTransition(a, a.params, name, argc) } func (a FuncState) Reference(name string) Fsm { + a.lastStmtOffset = a.b.len() return reference(a, a.params, name) } func (a FuncState) Boolean(v bool) Fsm { - panic("implement me") + a.lastStmtOffset = a.b.len() + return constant(a, a.params, rideBoolean(v)) } func (a FuncState) String(s string) Fsm { - panic("implement me") + a.lastStmtOffset = a.b.len() + return constant(a, a.params, rideString(s)) } func (a FuncState) Condition() Fsm { + a.lastStmtOffset = a.b.len() return conditionalTransition(a, a.params) } func (a FuncState) TrueBranch() Fsm { - panic("implement me") + panic("Illegal call `TrueBranch` on `FuncState`") } func (a FuncState) FalseBranch() Fsm { - panic("implement me") + panic("Illegal call `FalseBranch` on `FuncState`") } func (a FuncState) Bytes(b []byte) Fsm { - panic("implement me") + a.lastStmtOffset = a.b.len() + return constant(a, a.params, rideBytes(b)) } func (a FuncState) Func(name string, args []string, _ string) Fsm { diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index f3bac355df..e9bd93e3f1 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -116,6 +116,11 @@ func (a *cell) set(u uniqueid, result rideType, fn rideFunction, position uint16 } } +func (a *cell) get(u uniqueid) (point, bool) { + rs, ok := a.values[u] + return rs, ok +} + type uniqueid = uint16 type references struct { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 7df3383884..0536f71e18 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -3,6 +3,12 @@ package ride // Initial state, contains only assigments and last expression. type MainState struct { params + retAssig uint16 +} + +func (a MainState) retAssigment(pos uint16) Fsm { + a.retAssig = pos + return a } func (a MainState) Property(name string) Fsm { diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 365e4b92a7..55b3c36fb1 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -6,6 +6,10 @@ type PropertyState struct { params } +func (a PropertyState) retAssigment(pos uint16) Fsm { + panic("implement me") +} + func propertyTransition(prev Fsm, params params, name string) Fsm { return &PropertyState{ params: params, diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 556add21e7..051cc22d9c 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -16,6 +16,7 @@ type Fsm interface { Bytes(b []byte) Fsm Func(name string, args []string, invokeParam string) Fsm Property(name string) Fsm + retAssigment(pos uint16) Fsm } type uniqid struct { diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go new file mode 100644 index 0000000000..2171db0622 --- /dev/null +++ b/pkg/ride/decompiler.go @@ -0,0 +1,118 @@ +package ride + +import ( + "fmt" + "strings" +) + +type detreeType = func(s *strings.Builder, tree Node) + +func prefix(s *strings.Builder, name string, nodes []Node, f detreeType) { + s.WriteString(name) + s.WriteString("(") + for i, a := range nodes { + f(s, a) + if i+1 != len(nodes) { + s.WriteString(",") + } + } + s.WriteString(")") +} + +func infix(s *strings.Builder, name string, nodes []Node, f detreeType) { + s.WriteString("(") + f(s, nodes[0]) + s.WriteString(fmt.Sprintf(" %s ", name)) + f(s, nodes[1]) + s.WriteString(")") +} + +var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f detreeType){ + "0": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + s.WriteString("(") + f(s, nodes[0]) + s.WriteString(" == ") + f(s, nodes[1]) + s.WriteString(")") + }, + "100": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "+", nodes, f) + }, + "101": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "-", nodes, f) + }, + "1": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "instanceOf", nodes, f) + }, + "1052": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "getBinary", nodes, f) + }, +} + +func defunc(s *strings.Builder, name string, nodes []Node, f detreeType) { + if v, ok := defuncs[name]; ok { + v(s, name, nodes, f) + } else { + s.WriteString(name) + s.WriteString("(") + for _, a := range nodes { + detree(s, a) + s.WriteString(",") + } + s.WriteString(")") + } +} + +func Decompiler(tree Node) string { + s := &strings.Builder{} + detree(s, tree) + return s.String() +} + +func detree(s *strings.Builder, tree Node) { + switch n := tree.(type) { + case *FunctionDeclarationNode: + s.WriteString(fmt.Sprintf("func %s(", n.Name)) + for i, a := range n.Arguments { + s.WriteString(a) + if i+1 != len(n.Arguments) { + s.WriteString(",") + } + } + s.WriteString(") { ") + detree(s, n.Body) + 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) + case *ConditionalNode: + s.WriteString(fmt.Sprintf("if (")) + detree(s, n.Condition) + s.WriteString(") { ") + detree(s, n.TrueExpression) + s.WriteString(" } else { ") + detree(s, n.FalseExpression) + s.WriteString(" }") + case *FunctionCallNode: + defunc(s, n.Name, n.Arguments, detree) + case *ReferenceNode: + s.WriteString(n.Name) + case *StringNode: + s.WriteString(`"`) + s.WriteString(n.Value) + s.WriteString(`"`) + case *PropertyNode: + detree(s, n.Object) + s.WriteString(".") + s.WriteString(n.Name) + case *BooleanNode: + s.WriteString(fmt.Sprintf("%t", n.Value)) + case *LongNode: + s.WriteString(fmt.Sprintf("%d", n.Value)) + default: + panic(fmt.Sprintf("unknown type %T", n)) + } +} diff --git a/pkg/ride/result.go b/pkg/ride/result.go index 703ed35e3e..01b512fdbe 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -5,12 +5,14 @@ import "github.com/wavesplatform/gowaves/pkg/proto" type RideResult interface { Result() bool UserError() string - ScriptActions() []proto.ScriptAction + ScriptActions() proto.ScriptActions + Eq(RideResult) bool } type ScriptResult struct { - res bool - msg string + res bool + msg string + operations int } func (r ScriptResult) Result() bool { @@ -21,14 +23,24 @@ func (r ScriptResult) UserError() string { return r.msg } -func (r ScriptResult) ScriptActions() []proto.ScriptAction { +func (r ScriptResult) ScriptActions() proto.ScriptActions { return nil } +func (r ScriptResult) Eq(other RideResult) bool { + switch a := other.(type) { + case ScriptResult: + return a.res == r.res && a.msg == r.msg + default: + return false + } +} + type DAppResult struct { - res bool // true - success, false - call failed, read msg - actions []proto.ScriptAction - msg string + res bool // true - success, false - call failed, read msg + actions proto.ScriptActions + msg string + operations int } func (r DAppResult) Result() bool { @@ -39,6 +51,15 @@ func (r DAppResult) UserError() string { return r.msg } -func (r DAppResult) ScriptActions() []proto.ScriptAction { +func (r DAppResult) ScriptActions() proto.ScriptActions { return r.actions } + +func (r DAppResult) Eq(other RideResult) bool { + switch a := other.(type) { + case DAppResult: + return a.res == r.res && a.msg == r.msg && a.actions.Eq(r.actions) + default: + return false + } +} diff --git a/pkg/ride/result_test.go b/pkg/ride/result_test.go new file mode 100644 index 0000000000..97e982b644 --- /dev/null +++ b/pkg/ride/result_test.go @@ -0,0 +1,11 @@ +package ride + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestResult_Eq(t *testing.T) { + require.True(t, ScriptResult{}.Eq(ScriptResult{})) +} diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 00d2a53265..ab2940dc0e 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -13,7 +13,7 @@ func CallVerifier2(env RideEnvironment, tree *Tree) (RideResult, error) { return e.evaluate() } -func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { +func CallVerifier3(env RideEnvironment, tree *Tree) (RideResult, error) { compiled, err := CompileSimpleScript(tree) if err != nil { return nil, errors.Wrap(err, "call compile script") @@ -21,7 +21,24 @@ func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { return compiled.Run(env) } +func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { + //r, err := CallVerifier3(env, tree) + //if err != nil { + // return nil, err + //} + + r, err := CallVerifier2(env, tree) + if err != nil { + return nil, err + } + //if !r.Eq(r2) { + // return nil, errors.New("R1 != R2: failed to call account script on transaction ") + //} + return r, nil +} + func CallFunction(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { + panic("CallFunction called") if name == "" { name = "default" } diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index 31aabc59fa..a87e7f3835 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -227,7 +227,7 @@ func (e *treeEvaluator) evaluate() (RideResult, error) { if err != nil { return nil, errors.Wrap(err, "failed to convert evaluation result") } - return DAppResult{true, actions, ""}, nil + return DAppResult{res: true, actions: actions, msg: ""}, nil case rideList: actions := make([]proto.ScriptAction, len(res)) for i, item := range res { @@ -243,11 +243,6 @@ func (e *treeEvaluator) evaluate() (RideResult, error) { } } -// -//func (e *treeEvaluator) exceeded() bool { -// return e.limit > 0 && e.cost >= e.limit -//} - func isThrow(r rideType) bool { return r.instanceOf() == "Throw" } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 524ded6328..bd9bdf6dd6 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -53,7 +53,11 @@ func (m *vm) run() (RideResult, error) { m.ip = pos } case OpJumpIfFalse: - pos := m.arg16() + posTrue := m.arg16() + posFalse := m.arg16() + posNext := m.arg16() + m.jmps = append(m.jmps, posNext) + val, err := m.pop() if err != nil { return nil, errors.Wrap(err, "OpJumpIfFalse") @@ -62,8 +66,10 @@ func (m *vm) run() (RideResult, error) { if !ok { return nil, errors.Errorf("not a boolean value '%v' of type '%T'", m.current(), m.current()) } - if !v { - m.ip = pos + if v { + m.ip = posTrue + } else { + m.ip = posFalse } case OpProperty: obj, err := m.pop() @@ -105,6 +111,9 @@ func (m *vm) run() (RideResult, error) { if err != nil { return nil, err } + if isThrow(res) { + return nil, errors.Errorf("terminated execution by throw with message %q", res) + } m.push(res) case OpReturn: l := len(m.jmps) @@ -116,7 +125,7 @@ func (m *vm) run() (RideResult, error) { } switch tv := v.(type) { case rideBoolean: - return ScriptResult{res: bool(tv)}, nil + return ScriptResult{res: bool(tv), operations: numOperations}, nil default: return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) } diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index b591e5f104..dc4bebb514 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -82,18 +82,21 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn } func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockInfo *proto.BlockInfo, initialisation bool) error { - senderAddr, err := proto.NewAddressFromPublicKey(a.settings.AddressSchemeCharacter, tx.GetSenderPK()) + id, err := tx.GetID(a.settings.AddressSchemeCharacter) if err != nil { return err } - tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) + idString := base58.Encode(id) + senderAddr, err := proto.NewAddressFromPublicKey(a.settings.AddressSchemeCharacter, tx.GetSenderPK()) if err != nil { return err } - id, err := tx.GetID(a.settings.AddressSchemeCharacter) + tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) if err != nil { return err } + zap.S().Error(ride.Decompiler(tree.Verifier)) + env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) @@ -104,14 +107,23 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } - zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) + //zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) r, err := ride.CallVerifier(env, tree) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } + + //r2, err := ride.CallVerifier2(env, tree) + //if err != nil { + // return errors.Wrapf(err, "R2: failed to call account script on transaction '%s'", base58.Encode(id)) + //} + //if !r.Eq(r2) { + // return errors.Wrapf(err, "R1 != R2: failed to call account script on transaction '%s'", base58.Encode(id)) + //} + if !r.Result() { if r.UserError() != "" { - return errors.Errorf("account script on transaction '%s' failed with error: %v", base58.Encode(id), r.UserError()) + return errors.Errorf("account script on transaction '%s' failed with error: %v", idString, r.UserError()) } return errs.NewTransactionNotAllowedByScript("script failed", id) } From f4c6943c642e81169da7f81d17e215ecba217ffa Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 1 Dec 2020 20:44:55 +0300 Subject: [PATCH 13/55] Cache function result as variable. --- cmd/node/node.go | 2 +- pkg/ride/compiler2.go | 137 +++++++++++++- pkg/ride/compiler2_test.go | 298 ++++++++++++++++++++++++------- pkg/ride/compiler_assigment.go | 41 +++-- pkg/ride/compiler_call_system.go | 8 +- pkg/ride/compiler_call_user.go | 33 +++- pkg/ride/compiler_conditional.go | 6 +- pkg/ride/compiler_func.go | 30 ++-- pkg/ride/compiler_helpers.go | 16 +- pkg/ride/compiler_main.go | 4 +- pkg/ride/compiler_property.go | 9 +- pkg/ride/compiler_state.go | 12 +- pkg/ride/decompiler.go | 5 + pkg/ride/executable.go | 2 - pkg/ride/functions_predefined.go | 18 +- pkg/ride/opcodes.go | 3 +- pkg/ride/result.go | 9 +- pkg/ride/tree_evaluation.go | 49 +++-- pkg/ride/vm.go | 47 +++-- pkg/state/script_caller.go | 25 ++- 20 files changed, 586 insertions(+), 168 deletions(-) diff --git a/cmd/node/node.go b/cmd/node/node.go index fe260e1fb7..022339cf47 100644 --- a/cmd/node/node.go +++ b/cmd/node/node.go @@ -87,7 +87,7 @@ var ( var defaultPeers = map[string]string{ "mainnet": "35.156.19.4:6868,52.50.69.247:6868,52.52.46.76:6868,52.57.147.71:6868,52.214.55.18:6868,54.176.190.226:6868", "testnet": "159.69.126.149:6863,94.130.105.239:6863,159.69.126.153:6863,94.130.172.201:6863", - "stagenet": "217.100.219.251:6861", + "stagenet": "217.100.219.251:6861,49.12.15.166:6862", } type Scheduler interface { diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index f59d99ee42..b47ea8bf5c 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -2,6 +2,7 @@ package ride import ( "github.com/pkg/errors" + "github.com/wavesplatform/gowaves/pkg/proto" ) func ccc(f Fsm, node Node) (Fsm, error) { @@ -66,11 +67,90 @@ func ccc(f Fsm, node Node) (Fsm, error) { } } -func CompileSimpleScript(t *Tree) (*Executable, error) { - return compileSimpleScript(t.LibVersion, t.Verifier) +func CompileVerifier(txID string, tree *Tree) (*Executable, error) { + //s, err := newEvaluationScope(tree.LibVersion, env) + //if err != nil { + // return nil, errors.Wrap(err, "failed to create scope") + //} + if tree.IsDApp() { + if tree.HasVerifier() { + _, ok := tree.Verifier.(*FunctionDeclarationNode) + if !ok { + return nil, errors.New("invalid verifier declaration") + } + //for _, declaration := range tree.Declarations { + // err = s.declare(declaration) + // if err != nil { + // return nil, errors.Wrap(err, "invalid declaration") + // } + //} + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier), nil) + //s.constants[verifier.invocationParameter] = esConstant{c: newTx} + //return &treeEvaluator{ + // dapp: tree.IsDApp(), + // f: verifier.Body, // In DApp verifier is a function, so we have to pass its body + // s: s, + // env: env, + //}, nil + } + return nil, errors.New("no verifier declaration") + } + return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, nil) } -func compileSimpleScript(libVersion int, node Node) (*Executable, error) { +type namedArgument struct { + name string + arg rideType +} + +func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments) (*Executable, error) { + //s, err := newEvaluationScope(tree.LibVersion, env) + //if err != nil { + // return nil, errors.Wrap(err, "failed to create scope") + //} + //for i, declaration := range tree.Declarations { + // //err = s.declare(declaration) + // //if err != nil { + // // return nil, errors.Wrap(err, "invalid declaration") + // //} + // zap.S().Errorf("decl #%d ?? %s", i, Decompiler(declaration)) + //} + if !tree.IsDApp() { + return nil, errors.Errorf("unable to call function '%s' on simple script", name) + } + for i := 0; i < len(tree.Functions); i++ { + function, ok := tree.Functions[i].(*FunctionDeclarationNode) + if !ok { + return nil, errors.New("invalid callable declaration") + } + if function.Name == name { + //s.constants[function.invocationParameter] = esConstant{c: newInvocation} + if l := len(args); l != len(function.Arguments) { + return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) + } + applyArgs := make([]namedArgument, 0, len(args)) + for i, arg := range args { + a, err := convertArgument(arg) + if err != nil { + return nil, errors.Wrapf(err, "failed to call function '%s'", name) + } + //s.pushValue(function.Arguments[i], a) + applyArgs = append(applyArgs, namedArgument{ + name: function.Arguments[i], + arg: a, + }) + } + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), applyArgs) + //return &treeEvaluator{dapp: true, f: function.Body, s: s, env: env}, nil + } + } + return nil, errors.Errorf("function '%s' not found", name) + + //return compileFunction(t.LibVersion, t) +} + +/* +func compileVerifier(libVersion int, node Node) (*Executable, error) { fCheck, err := selectFunctionChecker(libVersion) if err != nil { return nil, err @@ -101,5 +181,56 @@ func compileSimpleScript(libVersion int, node Node) (*Executable, error) { f = f.Return() return f.(BuildExecutable).BuildExecutable(libVersion), nil +} +*/ + +func compileFunction(txID string, libVersion int, nodes []Node, args []namedArgument) (*Executable, error) { + fCheck, err := selectFunctionChecker(libVersion) + if err != nil { + return nil, err + } + u := &uniqid{} + b := newBuilder() + r := newReferences(nil) + c := newCell() + b.writeByte(OpReturn) + + params := params{ + b: b, + r: r, + f: fCheck, + u: u, + c: c, + txID: txID, + } + for k, v := range predefinedFunctions { + params.addPredefined(k, v.id, v.f) + } + + //invokParam := nodes[len(nodes)-1].(*FunctionDeclarationNode).invocationParameter + //if invokParam != "" { + // params.r.set( + // invokParam, + // math.MaxUint16, + // ) + //} + for _, arg := range args { + params.r.set( + arg.name, + params.constant(arg.arg), + ) + } + + f := NewMain(params) + for _, node := range nodes { + f, err = ccc(f, node) + if err != nil { + return nil, err + } + } + // Just to write `OpReturn` to bytecode. + f = f.Return() + + return f.(BuildExecutable).BuildExecutable(libVersion), nil } diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index ab88fe08c3..ee2fa0a524 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -13,45 +13,6 @@ import ( "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" ) -func Test_ccc(t *testing.T) { - - version := 3 - - // let x = 5; 6 > x - ast := &AssignmentNode{ - Name: "x", - Expression: &LongNode{ - Value: 5, - }, - Block: &FunctionCallNode{ - Name: "102", // gt - Arguments: []Node{ - &LongNode{ - Value: 6, - }, - &ReferenceNode{ - Name: "x", - }, - }, - }, - } - rs, err := compileSimpleScript(version, ast) - - fSelect, err := selectFunctions(version) - require.NoError(t, err) - - v := vm{ - code: rs.ByteCode, - ip: int(rs.EntryPoints[""]), - constants: rs.Constants, - functions: fSelect, - } - - sr, err := v.run() - require.NoError(t, err) - require.True(t, sr.Result()) -} - func Test22(t *testing.T) { state := &MockSmartState{ NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { @@ -81,7 +42,9 @@ func Test22(t *testing.T) { res bool }{ {`V1: true`, "AQa3b8tH", nil, true}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, + {`V1: false`, `AQfeYll6`, nil, false}, + {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, {`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", env, false}, {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, @@ -102,10 +65,9 @@ func Test22(t *testing.T) { {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - {`false`, `AQfeYll6`, nil, false}, + {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, - // Global variables {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, @@ -125,7 +87,7 @@ func Test22(t *testing.T) { require.NoError(t, err, test.comment) assert.NotNil(t, tree, test.comment) - script, err := CompileSimpleScript(tree) + script, err := CompileVerifier(tree) require.NoError(t, err, test.comment) assert.NotNil(t, script, test.comment) @@ -194,13 +156,14 @@ func TestCallExternal(t *testing.T) { }, } - f, err := compileSimpleScript(3, n) + f, err := compileVerifier(3, n) require.NoError(t, err) require.Equal(t, []byte{ - OpPush, 0, 0, - OpPush, 0, 1, + OpReturn, + OpRef, 0, 1, + OpRef, 0, 2, OpExternalCall, 0, 3, 0, 2, OpReturn, }, @@ -221,7 +184,7 @@ func TestIfConditionRightByteCode(t *testing.T) { }, } - f, err := compileSimpleScript(3, n) + f, err := compileVerifier(3, n) require.NoError(t, err) require.Equal(t, @@ -266,22 +229,23 @@ func TestDoubleCall(t *testing.T) { }, } - f, err := compileSimpleScript(3, n) + f, err := compileVerifier(3, n) require.NoError(t, err) require.Equal(t, []byte{ + OpReturn, OpRef, 0, 1, OpReturn, - OpCall, 0, 0, + OpCall, 0, 1, OpRef, 0, 3, OpExternalCall, 0, 3, 0, 2, OpReturn, }, f.ByteCode) - require.EqualValues(t, 4, f.EntryPoints[""]) + require.EqualValues(t, 5, f.EntryPoints[""]) rs, err := f.Run(nil) require.NoError(t, err) @@ -305,25 +269,26 @@ func TestCallWithConstArg(t *testing.T) { invocationParameter: "", } - f, err := compileSimpleScript(3, n) + f, err := compileVerifier(3, n) require.NoError(t, err) bt := []byte{ - //OpUseArg, 0, 1, OpReturn, // arguments section + OpReturn, OpRef, 0, 1, // Function execution code. One line: reference to `v` argument. OpReturn, // call function - OpSetArg, 0, 2, 0, 1, - OpCall, 0, 0, + OpSetArg, 0, 3, 0, 1, + OpCall, 0, 1, OpReturn, } + //require.Equal(t, 1, 1, bt) require.Equal(t, bt, f.ByteCode) - f.ByteCode = bt - f.EntryPoints[""] = 4 + //f.ByteCode = bt + //f.EntryPoints[""] = 4 rs, err := f.Run(nil) require.NoError(t, err) @@ -357,7 +322,7 @@ func TestMultipleCallConstantFuncArgument(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileSimpleScript(tree) + script, err := CompileVerifier(tree) require.NoError(t, err) assert.NotNil(t, script) @@ -368,7 +333,7 @@ func TestMultipleCallConstantFuncArgument(t *testing.T) { assert.True(t, ok) assert.Equal(t, true, r.Result()) - //f, err := compileSimpleScript(3, n) + //f, err := compileVerifier(3, n) //require.NoError(t, err) //require.Equal(t, @@ -467,7 +432,7 @@ func TestCompileDapp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileSimpleScript(tree) + script, err := CompileVerifier(tree) require.NoError(t, err) assert.NotNil(t, script) @@ -527,7 +492,7 @@ func Test2121(t *testing.T) { t.Log(Decompiler(tree.Verifier)) - script, err := CompileSimpleScript(tree) + script, err := CompileVerifier(tree) require.NoError(t, err) assert.NotNil(t, script) @@ -584,7 +549,7 @@ func TestIfStmt(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileSimpleScript(tree) + script, err := CompileVerifier(tree) require.NoError(t, err) assert.NotNil(t, script) @@ -635,7 +600,7 @@ AwQAAAACZGQJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAABHRoaXMCAAAAAmRkCgEAAAABZgAA */ func Test44(t *testing.T) { - source := "AwQAAAACZGQJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAABHRoaXMCAAAAAmRkCgEAAAABZgAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEHAAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAKQnl0ZVZlY3RvcgQAAAABYQUAAAAHJG1hdGNoMAkAAGUAAAACAAAAAAAAAAACAAAAAAAAAAABAAAAAAAAAAAABAAAAAFhCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFlBAAAAAFiCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFrBAAAAAFjCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFrBAAAAAFkCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFlCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFnCQAAZAAAAAIJAABkAAAAAgkBAAAAAWYAAAABAgAAAAFnCQEAAAABZgAAAAECAAAAAWgJAQAAAAV2YWx1ZQAAAAEJAQAAAAFmAAAAAQIAAAABaQMDAwMDAwMJAAAAAAAAAgUAAAACZGQAAAAAAAAAAAEJAAAAAAAAAgUAAAABYQAAAAAAAAAABQcJAAAAAAAAAgUAAAABYgkBAAAADXBhcnNlSW50VmFsdWUAAAABAgAAAAEwBwkAAAAAAAACBQAAAAFjAAAAAAAAAAAEBwkAAAAAAAACBQAAAAFkCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAECAAAAATEHCQAAAAAAAAIFAAAAAWUAAAAAAAAAAAQHCQAAAAAAAAIFAAAAAWcJAQAAAA1wYXJzZUludFZhbHVlAAAAAQIAAAABMAcGCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAgFAAAAAnR4AAAAD3NlbmRlclB1YmxpY0tlebYLD8w=" + source := "AwQAAAALc3RhcnRIZWlnaHQAAAAAAAACvgAEAAAACnN0YXJ0UHJpY2UAAAAAAAX14QAEAAAACGludGVydmFsCQAAaAAAAAIAAAAAAAAAIj4AAAAAAAAAADwEAAAAA2V4cAkAAGgAAAACCQAAaAAAAAIAAAAAAAAAoyAAAAAAAAAAADwAAAAAAAAAA+gEAAAAB1dBVkVTSWQBAAAABBOr2TMEAAAAByRtYXRjaDAFAAAAAnR4AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBAAAAAFlBQAAAAckbWF0Y2gwBAAAAAV5ZWFycwkAAGkAAAACCQAAZQAAAAIFAAAABmhlaWdodAUAAAALc3RhcnRIZWlnaHQFAAAACGludGVydmFsAwMJAABnAAAAAggFAAAAAWUAAAAFcHJpY2UJAABoAAAAAgUAAAAKc3RhcnRQcmljZQkAAGQAAAACAAAAAAAAAAABBQAAAAV5ZWFycwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQgICAUAAAABZQAAAAlzZWxsT3JkZXIAAAAJYXNzZXRQYWlyAAAACnByaWNlQXNzZXQHCQAAZwAAAAIIBQAAAAFlAAAABmFtb3VudAAAAAAABfXhAAcGQlqguw==" src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -644,7 +609,7 @@ func Test44(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileSimpleScript(tree) + script, err := CompileVerifier(tree) require.NoError(t, err) assert.NotNil(t, script) @@ -658,3 +623,210 @@ func Test44(t *testing.T) { //assert.Equal(t, true, r.Result()) } + +/* + +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) { + source := `BAQAAAALb3JhY2xlc0xpc3QJAARMAAAAAgIAAAAjM01TTk1jcXl3ZWlNOWNXcHZmNEZuOEdBV2V1UHN0eGoyaEsFAAAAA25pbAoBAAAAGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQAAAAIAAAAHYWRkcmVzcwAAAANrZXkAAAAAAAAAAAAKAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgAAAAVvd25lcgAAAAZoZWlnaHQJAQAAABhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABBQAAAAVvd25lcgUAAAAGaGVpZ2h0CQAAAAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAAUAAAAGaGVpZ2h0AAAAAAAAAAABHUHhjA==` + + 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") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + t.Logf("acc: %q, key %s", account, key) + return &proto.IntegerDataEntry{ + Value: 0, + }, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + thisFunc: func() rideType { + return rideAddress{} + }, + heightFunc: func() rideInt { + return 100500 + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + res, err := script.Run(env) + require.NoError(t, err) + assert.NotNil(t, res) + r, ok := res.(ScriptResult) + assert.True(t, ok) + assert.Equal(t, true, r.Result()) +} + +func Test888(t *testing.T) { + source := `BAoBAAAAAWYAAAAACQAAAgAAAAECAAAAATEKAQAAAAJmMgAAAAIAAAAFb3duZXIAAAAGaGVpZ2h0BQAAAAZoZWlnaHQJAAAAAAAAAgkBAAAAAmYyAAAAAgkBAAAAAWYAAAAABQAAAAZoZWlnaHQAAAAAAAAAAAFFcqW2` + + 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") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + t.Logf("acc: %q, key %s", account, key) + return &proto.IntegerDataEntry{ + Value: 0, + }, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + thisFunc: func() rideType { + return rideAddress{} + }, + heightFunc: func() rideInt { + return 1 + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + _, err = script.Run(env) + require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"") +} + +/* + +{-# STDLIB_VERSION 4 #-} +{-# CONTENT_TYPE EXPRESSION #-} +{-# SCRIPT_TYPE ACCOUNT #-} + +func f() = { + getIntegerValue(this, "1") +} + +func f2(value: Int) = { + value == value +} + +f2(f()) + +*/ +func TestNoDuplicateCallToState(t *testing.T) { + source := `BAoBAAAAAWYAAAAACQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAAR0aGlzAgAAAAExCgEAAAACZjIAAAABAAAABXZhbHVlCQAAAAAAAAIFAAAABXZhbHVlBQAAAAV2YWx1ZQkBAAAAAmYyAAAAAQkBAAAAAWYAAAAAjuqz7g==` + + alreadyCalled := false + + 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") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + if alreadyCalled { + panic("duplicate call") + } + alreadyCalled = true + return &proto.IntegerDataEntry{ + Value: 0, + }, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + thisFunc: func() rideType { + return rideAddress{} + }, + heightFunc: func() rideInt { + return 1 + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier(tree) + require.NoError(t, err) + assert.NotNil(t, script) + + _, err = script.Run(env) + require.NoError(t, err) +} diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index af62a3cead..a9c86c0191 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -3,14 +3,15 @@ package ride // Assigment: let x = 5 type AssigmentState struct { params - prev Fsm - name string - offset uint16 - ret uint16 + prev Fsm + name string + startedAt uint16 + //ret uint16 + constant rideType } -func (a AssigmentState) retAssigment(pos uint16) Fsm { - a.ret = pos +func (a AssigmentState) retAssigment(startedAt uint16, endedAt uint16) Fsm { + //a.ret = pos return a } @@ -23,7 +24,8 @@ func (a AssigmentState) Func(name string, args []string, invoke string) Fsm { } func (a AssigmentState) Bytes(b []byte) Fsm { - return bts(a, a.params, b) + a.constant = rideBytes(b) + return a } func (a AssigmentState) Condition() Fsm { @@ -39,11 +41,13 @@ func (a AssigmentState) FalseBranch() Fsm { } func (a AssigmentState) String(s string) Fsm { - return constant(a, a.params, rideString(s)) + a.constant = rideString(s) + return a } func (a AssigmentState) Boolean(v bool) Fsm { - return boolean(a, a.params, v) + a.constant = rideBoolean(v) + return a } func assigmentFsmTransition(prev Fsm, params params, name string) Fsm { @@ -52,10 +56,10 @@ func assigmentFsmTransition(prev Fsm, params params, name string) Fsm { func newAssigmentFsm(prev Fsm, p params, name string) Fsm { return AssigmentState{ - prev: prev, - params: p, - name: name, - offset: p.b.len(), + prev: prev, + params: p, + name: name, + startedAt: p.b.len(), } } @@ -70,13 +74,18 @@ func (a AssigmentState) Return() Fsm { a.b.ret() // store reference on variable and it's offset. n := a.u.next() - a.c.set(n, nil, nil, a.offset) + if a.constant != nil { + a.c.set(n, a.constant, nil, 0, a.name) + } else { + a.c.set(n, nil, nil, a.startedAt, a.name) + } a.r.set(a.name, n) - return a.prev.retAssigment(a.params.b.len()) + return a.prev.retAssigment(a.startedAt, a.params.b.len()) } func (a AssigmentState) Long(value int64) Fsm { - return long(a, a.params, value) + a.constant = rideInt(value) + return a } func (a AssigmentState) Call(name string, argc uint16) Fsm { diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index ab009fd81a..e0042eb441 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -12,11 +12,11 @@ type CallSystemState struct { argn []uint16 // Position where we started write code for current state. startedAt uint16 - retAssig uint16 + //retAssig uint16 } -func (a CallSystemState) retAssigment(pos uint16) Fsm { - a.retAssig = pos +func (a CallSystemState) retAssigment(startedAt uint16, endedAt uint16) Fsm { + //a.retAssig = pos return a } @@ -84,7 +84,7 @@ func (a CallSystemState) Return() Fsm { panic(fmt.Sprintf("system function named `%s` not found", a.name)) } a.b.externalCall(n, a.argc) - return a.prev.retAssigment(a.startedAt) + return a.prev.retAssigment(a.startedAt, a.b.len()) } func (a CallSystemState) Call(name string, argc uint16) Fsm { diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 95dd90305e..7ee3bc3b63 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -9,19 +9,26 @@ type CallUserState struct { name string argc uint16 // positions of arguments - argn []uniqueid + argn []uniqueid + ret func(s CallUserState, at uint16, to uint16) + startedAt uint16 } -func (a CallUserState) retAssigment(pos uint16) Fsm { - panic("implement me") +func (a CallUserState) retAssigment(startedAt uint16, endedAt uint16) Fsm { + if a.ret != nil { + a.ret(a, startedAt, endedAt) + } + a.ret = nil + return a } func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { return &CallUserState{ - prev: prev, - params: params, - name: name, - argc: argc, + prev: prev, + params: params, + name: name, + argc: argc, + startedAt: params.b.len(), } } @@ -91,10 +98,20 @@ func (a CallUserState) Return() Fsm { } a.b.call(point.position, a.argc) - return a.prev + return a.prev.retAssigment(a.startedAt, a.b.len()) } func (a CallUserState) Call(name string, argc uint16) Fsm { + n := a.u.next() + a.c.set(n, nil, nil, 0, fmt.Sprintf("function as paramentr: %s$%d", name, n)) + a.argn = append(a.argn, n) + if a.ret != nil { + panic("already assigned") + } + a.ret = func(state CallUserState, startedAt uint16, endedAt uint16) { + a.b.writeByte(OpCache) + a.b.write(encode(n)) + } return callTransition(a, a.params, name, argc) } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 249e4e5afb..c11dbee5de 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -30,8 +30,8 @@ type ConditionalState struct { rets []uint16 } -func (a ConditionalState) retAssigment(pos uint16) Fsm { - a.retAssig = pos +func (a ConditionalState) retAssigment(startedAt uint16, endedAt uint16) Fsm { + //a.retAssig = pos return a } @@ -83,7 +83,7 @@ func (a ConditionalState) Return() Fsm { a.b.patch(a.patchTruePosition, encode(a.rets[1])) a.b.patch(a.patchFalsePosition, encode(a.rets[2])) a.b.patch(a.patchNextPosition, encode(a.b.len())) - return a.prev.retAssigment(a.startedAt) + return a.prev.retAssigment(a.startedAt, a.b.len()) } func (a ConditionalState) Long(value int64) Fsm { diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index a0a70eb40b..e84e6e1c9e 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -24,10 +24,11 @@ type FuncState struct { globalScope *references invokeParam string lastStmtOffset uint16 + startedAt uint16 } -func (a FuncState) retAssigment(pos uint16) Fsm { - a.lastStmtOffset = pos +func (a FuncState) retAssigment(startedAt uint16, endedAt uint16) Fsm { + a.lastStmtOffset = startedAt return a } @@ -36,6 +37,7 @@ func (a FuncState) Property(name string) Fsm { } func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { + startedAt := params.b.len() // save reference to global scope, where code lower that function will be able to use it. globalScope := params.r // all variable we add only visible to current scope, @@ -50,15 +52,16 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP // assume that it's verifier if invokeParam != "" { // tx - pos, ok := params.r.get("tx") - if !ok { - panic("no `tx` in function call") - } - params.b.writeByte(OpExternalCall) - params.b.write(encode(math.MaxUint16)) - params.b.write(encode(0)) - params.b.writeByte(OpReturn) - params.r.set(invokeParam, pos) + //pos, ok := params.r.get("tx") + //if !ok { + // panic("no `tx` in function call") + //} + //params.b.writeByte(OpExternalCall) + //params.b.write(encode(math.MaxUint16)) + //params.b.write(encode(0)) + //params.b.writeByte(OpReturn) + //params.r.set(invokeParam, pos) + params.r.set(invokeParam, math.MaxUint16) } return &FuncState{ @@ -69,6 +72,7 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP //offset: params.b.len(), globalScope: globalScope, invokeParam: invokeParam, + startedAt: startedAt, } } @@ -79,7 +83,7 @@ func (a FuncState) Assigment(name string) Fsm { func (a FuncState) Return() Fsm { funcID := a.params.u.next() a.globalScope.set(a.name, funcID) - a.params.c.set(funcID, nil, nil, a.lastStmtOffset) + a.params.c.set(funcID, nil, nil, a.lastStmtOffset, a.name) // TODO clean args a.b.ret() @@ -90,7 +94,7 @@ func (a FuncState) Return() Fsm { a.b.write(encode(a.lastStmtOffset)) } - return a.prev.retAssigment(a.b.len()) + return a.prev.retAssigment(a.startedAt, a.b.len()) } func (a FuncState) Long(value int64) Fsm { diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index e9bd93e3f1..0eb52a3cd6 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -93,9 +93,10 @@ func (b *builder) write(i []byte) { } type point struct { - position uint16 - value rideType - fn rideFunction + position uint16 + value rideType + fn rideFunction + debugInfo string } type cell struct { @@ -108,11 +109,12 @@ func newCell() *cell { } } -func (a *cell) set(u uniqueid, result rideType, fn rideFunction, position uint16) { +func (a *cell) set(u uniqueid, result rideType, fn rideFunction, position uint16, debug string) { a.values[u] = point{ - position: position, - value: result, - fn: fn, + position: position, + value: result, + fn: fn, + debugInfo: debug, } } diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 0536f71e18..dee442d467 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -6,8 +6,8 @@ type MainState struct { retAssig uint16 } -func (a MainState) retAssigment(pos uint16) Fsm { - a.retAssig = pos +func (a MainState) retAssigment(startedAt uint16, endedAt uint16) Fsm { + a.retAssig = startedAt return a } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 55b3c36fb1..de72180ae6 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -6,8 +6,9 @@ type PropertyState struct { params } -func (a PropertyState) retAssigment(pos uint16) Fsm { - panic("implement me") +func (a PropertyState) retAssigment(startedAt uint16, endedAt uint16) Fsm { + //panic("implement me") + return a } func propertyTransition(prev Fsm, params params, name string) Fsm { @@ -34,7 +35,7 @@ func (a PropertyState) Long(value int64) Fsm { } func (a PropertyState) Call(name string, argc uint16) Fsm { - panic("Illegal call `Call` on PropertyState") + return callTransition(a, a.params, name, argc) } func (a PropertyState) Reference(name string) Fsm { @@ -70,5 +71,5 @@ func (a PropertyState) Func(name string, args []string, invoke string) Fsm { } func (a PropertyState) Property(name string) Fsm { - panic("Illegal call `Property` on PropertyState") + return propertyTransition(a, a.params, name) } diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 051cc22d9c..3a1262d9ad 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -16,7 +16,7 @@ type Fsm interface { Bytes(b []byte) Fsm Func(name string, args []string, invokeParam string) Fsm Property(name string) Fsm - retAssigment(pos uint16) Fsm + retAssigment(startedAt uint16, endedAt uint16) Fsm } type uniqid struct { @@ -45,16 +45,18 @@ type params struct { u *uniqid // Predefined variables. c *cell + // Transaction ID, for debug purpose. + txID string } func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) { a.r.set(name, id) - a.c.set(id, nil, fn, 0) + a.c.set(id, nil, fn, 0, name) } func (a *params) constant(value rideType) uniqueid { n := a.u.next() - a.c.set(n, value, nil, 0) + a.c.set(n, value, nil, 0, fmt.Sprintf("constant %q", value)) return n } @@ -83,7 +85,7 @@ func constant(a Fsm, params params, value rideType) Fsm { return a } -func putConstant(params params, rideType rideType) uint16 { +func putConstant(params params, rideType rideType) uniqueid { index := params.constant(rideType) return index } @@ -91,7 +93,7 @@ func putConstant(params params, rideType rideType) uint16 { func reference(f Fsm, params params, name string) Fsm { pos, ok := params.r.get(name) if !ok { - panic(fmt.Sprintf("reference %s not found", name)) + panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) } //params.b params.b.jump(pos) diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index 2171db0622..25f9b239a2 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -72,6 +72,9 @@ func Decompiler(tree Node) string { func detree(s *strings.Builder, tree Node) { switch n := tree.(type) { case *FunctionDeclarationNode: + if n.invocationParameter != "" { + s.WriteString("@" + n.invocationParameter + "@") + } s.WriteString(fmt.Sprintf("func %s(", n.Name)) for i, a := range n.Arguments { s.WriteString(a) @@ -112,6 +115,8 @@ func detree(s *strings.Builder, tree Node) { s.WriteString(fmt.Sprintf("%t", n.Value)) case *LongNode: s.WriteString(fmt.Sprintf("%d", n.Value)) + case nil: + // nothing default: panic(fmt.Sprintf("unknown type %T", n)) } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 6bf12fc06a..a76ddddcbd 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -29,7 +29,5 @@ func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { ref: a.References, } - //v.push(environment.transaction()) - return v.run() } diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index f1d02c6d20..3966f2ee3d 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -22,11 +22,21 @@ func this(env RideEnvironment, _ ...rideType) (rideType, error) { return env.this(), nil } +func height(env RideEnvironment, _ ...rideType) (rideType, error) { + return env.height(), nil +} + +func nilFunc(env RideEnvironment, _ ...rideType) (rideType, error) { + return rideList{}, nil +} + var predefinedFunctions = map[string]predefFunc{ - "tx": {id: math.MaxUint16 - 0, f: tx}, - "unit": {id: math.MaxUint16 - 1, f: unit}, - "NOALG": {id: math.MaxUint16 - 2, f: createNoAlg}, - "this": {id: math.MaxUint16 - 3, f: this}, + "tx": {id: math.MaxUint16 - 0, f: tx}, + "unit": {id: math.MaxUint16 - 1, f: unit}, + "NOALG": {id: math.MaxUint16 - 2, f: createNoAlg}, + "this": {id: math.MaxUint16 - 3, f: this}, + "height": {id: math.MaxUint16 - 4, f: height}, + "nil": {id: math.MaxUint16 - 5, f: nilFunc}, } var predefined *predef diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index acd8fe385b..2d8863c92c 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -16,8 +16,7 @@ const ( OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. OpSetArg //11 0xb - FROM (global) -> TO (local): Set value into cell. Two parameters: constant id and cell id. - OpUseArg //12 0xc - Use stored value in cell. One param: cell id. - OpCache //13 0xd - Put constant on stack. One parameter: constant ID. + OpCache //12 0xd - Put constant on stack. One parameter: constant ID. OpRef //14 0xe = ref id // odd, will be removed. diff --git a/pkg/ride/result.go b/pkg/ride/result.go index 01b512fdbe..58444abe1f 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -1,6 +1,9 @@ package ride -import "github.com/wavesplatform/gowaves/pkg/proto" +import ( + "github.com/stretchr/testify/assert" + "github.com/wavesplatform/gowaves/pkg/proto" +) type RideResult interface { Result() bool @@ -56,9 +59,9 @@ func (r DAppResult) ScriptActions() proto.ScriptActions { } func (r DAppResult) Eq(other RideResult) bool { - switch a := other.(type) { + switch other.(type) { case DAppResult: - return a.res == r.res && a.msg == r.msg && a.actions.Eq(r.actions) + return assert.ObjectsAreEqual(r, other) default: return false } diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index ab2940dc0e..6270a0f3ba 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -3,6 +3,7 @@ package ride import ( "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" + "go.uber.org/zap" ) func CallVerifier2(env RideEnvironment, tree *Tree) (RideResult, error) { @@ -13,32 +14,31 @@ func CallVerifier2(env RideEnvironment, tree *Tree) (RideResult, error) { return e.evaluate() } -func CallVerifier3(env RideEnvironment, tree *Tree) (RideResult, error) { - compiled, err := CompileSimpleScript(tree) +func CallVerifier3(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { + compiled, err := CompileVerifier(txID, tree) if err != nil { return nil, errors.Wrap(err, "call compile script") } return compiled.Run(env) } -func CallVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { - //r, err := CallVerifier3(env, tree) - //if err != nil { - // return nil, err - //} - - r, err := CallVerifier2(env, tree) +func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { + r, err := CallVerifier3(txID, env, tree) if err != nil { return nil, err } + + //r, err := CallVerifier2(env, tree) + //if err != nil { + // return nil, err + //} //if !r.Eq(r2) { // return nil, errors.New("R1 != R2: failed to call account script on transaction ") //} return r, nil } -func CallFunction(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - panic("CallFunction called") +func CallFunction3(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { if name == "" { name = "default" } @@ -48,3 +48,30 @@ func CallFunction(env RideEnvironment, tree *Tree, name string, args proto.Argum } return e.evaluate() } + +func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { + rs1, err := CallFunction3(env, tree, name, args) + if err != nil { + return nil, errors.Wrap(err, "call function by tree") + } + rs2, err := CallFunction2(txID, env, tree, name, args) + if err != nil { + return nil, errors.Wrap(err, "call function by vm") + } + if !rs1.Eq(rs2) { + zap.S().Errorf("result mismatch tree %+q vm %+q", rs1, rs2) + return nil, errors.New("result mismatch") + } + return rs2, nil +} + +func CallFunction2(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { + if name == "" { + name = "default" + } + f, err := CompileFunction(txID, tree, name, args) + if err != nil { + return nil, err + } + return f.Run(env) +} diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index bd9bdf6dd6..5c56168fc0 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -5,6 +5,7 @@ import ( //im "github.com/frozen/immutable_map" "github.com/pkg/errors" + "github.com/wavesplatform/gowaves/pkg/proto" ) type vm struct { @@ -17,13 +18,13 @@ type vm struct { stack []rideType functionName func(int) string jmps []int - cache map[int]rideType ref map[uint16]point + cache bool } func (m *vm) run() (RideResult, error) { numOperations := 0 - limitOperations := 10000 + limitOperations := 100000 if m.stack != nil { m.stack = m.stack[0:0] } @@ -46,12 +47,10 @@ func (m *vm) run() (RideResult, error) { } case OpJump: pos := m.arg16() - if rs, ok := m.cache[pos]; ok { - m.push(rs) - } else { - m.jmps = append(m.jmps, m.ip) - m.ip = pos - } + + m.jmps = append(m.jmps, m.ip) + m.ip = pos + case OpJumpIfFalse: posTrue := m.arg16() posFalse := m.arg16() @@ -109,7 +108,7 @@ func (m *vm) run() (RideResult, error) { } res, err := fn(m.env, in...) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "iteration %d", numOperations) } if isThrow(res) { return nil, errors.Errorf("terminated execution by throw with message %q", res) @@ -126,6 +125,22 @@ func (m *vm) run() (RideResult, error) { switch tv := v.(type) { case rideBoolean: return ScriptResult{res: bool(tv), operations: numOperations}, nil + case rideObject: + actions, err := objectToActions(m.env, tv) + if err != nil { + return nil, errors.Wrap(err, "failed to convert evaluation result") + } + return DAppResult{res: true, actions: actions, msg: ""}, nil + case rideList: + actions := make([]proto.ScriptAction, len(tv)) + for i, item := range tv { + a, err := convertToAction(m.env, item) + if err != nil { + return nil, errors.Wrap(err, "failed to convert evaluation result") + } + actions[i] = a + } + return DAppResult{res: true, actions: actions}, nil default: return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) } @@ -137,7 +152,19 @@ func (m *vm) run() (RideResult, error) { 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() + value, err := m.pop() + if err != nil { + return nil, errors.Wrap(err, "no value to cache") + } + m.ref[refID] = point{ + value: value, + } case OpRef: refID := m.uint16() @@ -159,7 +186,7 @@ func (m *vm) run() (RideResult, error) { } default: - return nil, errors.Errorf("unknown code %#x", op) + return nil, errors.Errorf("unknown code %#x, at iteration %d", op, numOperations) } } return nil, errors.New("broken code") diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index dc4bebb514..2b56bb0c24 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -58,7 +58,7 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return errors.Wrap(err, "failed to convert order") } - r, err := ride.CallVerifier(env, tree) + r, err := ride.CallVerifier("scriptCaller callAccountScriptWithOrder", env, tree) if err != nil { return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) } @@ -86,7 +86,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return err } - idString := base58.Encode(id) + txID := base58.Encode(id) senderAddr, err := proto.NewAddressFromPublicKey(a.settings.AddressSchemeCharacter, tx.GetSenderPK()) if err != nil { return err @@ -95,7 +95,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return err } - zap.S().Error(ride.Decompiler(tree.Verifier)) + //zap.S().Error(ride.Decompiler(tree.Verifier)) env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) if err != nil { @@ -108,7 +108,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } //zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) - r, err := ride.CallVerifier(env, tree) + r, err := ride.CallVerifier(txID, env, tree) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } @@ -123,7 +123,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if !r.Result() { if r.UserError() != "" { - return errors.Errorf("account script on transaction '%s' failed with error: %v", idString, r.UserError()) + return errors.Errorf("account script on transaction '%s' failed with error: %v", txID, r.UserError()) } return errs.NewTransactionNotAllowedByScript("script failed", id) } @@ -161,7 +161,7 @@ func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID cryp env.SetThisFromAssetInfo(assetInfo) } env.SetLastBlock(lastBlockInfo) - r, err := ride.CallVerifier(env, tree) + r, err := ride.CallVerifier("scriptCaller callAssetScriptCommon", env, tree) if err != nil { return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) } @@ -203,6 +203,8 @@ func (a *scriptCaller) callAssetScript(tx proto.Transaction, assetID crypto.Dige } func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWithProofs, lastBlockInfo *proto.BlockInfo, scriptAddress proto.Address, initialisation bool) (bool, []proto.ScriptAction, error) { + txID := tx.ID.String() + _ = txID env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) if err != nil { return false, nil, errors.Wrap(err, "failed to create RIDE environment") @@ -218,7 +220,16 @@ func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWit return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } env.ChooseSizeCheck(tree.LibVersion) - r, err := ride.CallFunction(env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + + for i, f := range tree.Functions { + rs := ride.Decompiler(f) + zap.S().Error(i, " == ", rs) + + } + + //zap.S().Error(ride.Decompiler(tree.)) + + r, err := ride.CallFunction(txID, env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } From ae6f02ab83efd853651741a2feb8078e0fa954ff Mon Sep 17 00:00:00 2001 From: Frozen Date: Wed, 2 Dec 2020 19:06:42 +0300 Subject: [PATCH 14/55] Function arguments. --- pkg/ride/compiler2.go | 68 +++++++++++++++++++------------- pkg/ride/compiler2_test.go | 26 ++++++------ pkg/ride/compiler_func.go | 27 ++++++++----- pkg/ride/executable.go | 5 +-- pkg/ride/tree_evaluation.go | 37 ++++++++++++----- pkg/ride/tree_evaluation_test.go | 62 ++++++++++++++--------------- pkg/ride/vm.go | 18 +++------ pkg/state/script_caller.go | 2 +- 8 files changed, 137 insertions(+), 108 deletions(-) diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index b47ea8bf5c..ecbe477d5f 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -84,7 +84,7 @@ func CompileVerifier(txID string, tree *Tree) (*Executable, error) { // return nil, errors.Wrap(err, "invalid declaration") // } //} - return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier), nil) + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier)) //s.constants[verifier.invocationParameter] = esConstant{c: newTx} //return &treeEvaluator{ // dapp: tree.IsDApp(), @@ -95,7 +95,7 @@ func CompileVerifier(txID string, tree *Tree) (*Executable, error) { } return nil, errors.New("no verifier declaration") } - return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, nil) + return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}) } type namedArgument struct { @@ -103,7 +103,9 @@ type namedArgument struct { arg rideType } -func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments) (*Executable, error) { +type functionArgumentsCount = int + +func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments) (*Executable, functionArgumentsCount, error) { //s, err := newEvaluationScope(tree.LibVersion, env) //if err != nil { // return nil, errors.Wrap(err, "failed to create scope") @@ -116,35 +118,41 @@ func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments) // zap.S().Errorf("decl #%d ?? %s", i, Decompiler(declaration)) //} if !tree.IsDApp() { - return nil, errors.Errorf("unable to call function '%s' on simple script", name) + return nil, 0, errors.Errorf("unable to call function '%s' on simple script", name) } for i := 0; i < len(tree.Functions); i++ { function, ok := tree.Functions[i].(*FunctionDeclarationNode) if !ok { - return nil, errors.New("invalid callable declaration") + return nil, 0, errors.New("invalid callable declaration") } if function.Name == name { //s.constants[function.invocationParameter] = esConstant{c: newInvocation} - if l := len(args); l != len(function.Arguments) { - return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) - } - applyArgs := make([]namedArgument, 0, len(args)) - for i, arg := range args { - a, err := convertArgument(arg) - if err != nil { - return nil, errors.Wrapf(err, "failed to call function '%s'", name) - } - //s.pushValue(function.Arguments[i], a) - applyArgs = append(applyArgs, namedArgument{ - name: function.Arguments[i], - arg: a, - }) + //if l := len(args); l != len(function.Arguments) { + // return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) + //} + //applyArgs := make([]rideType, 0, len(args)) + //for _, arg := range args { + // a, err := convertArgument(arg) + // if err != nil { + // return nil, errors.Wrapf(err, "failed to call function '%s'", name) + // } + // //s.pushValue(function.Arguments[i], a) + // applyArgs = append(applyArgs, a) + // //namedArgument{ + // // name: function.Arguments[i], + // // arg: a, + // //}) + //} + + rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function)) + if err != nil { + return rs, 0, err } - return compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), applyArgs) + return rs, len(function.Arguments), nil //return &treeEvaluator{dapp: true, f: function.Body, s: s, env: env}, nil } } - return nil, errors.Errorf("function '%s' not found", name) + return nil, 0, errors.Errorf("function '%s' not found", name) //return compileFunction(t.LibVersion, t) } @@ -184,7 +192,7 @@ func compileVerifier(libVersion int, node Node) (*Executable, error) { } */ -func compileFunction(txID string, libVersion int, nodes []Node, args []namedArgument) (*Executable, error) { +func compileFunction(txID string, libVersion int, nodes []Node) (*Executable, error) { fCheck, err := selectFunctionChecker(libVersion) if err != nil { return nil, err @@ -215,12 +223,16 @@ func compileFunction(txID string, libVersion int, nodes []Node, args []namedArgu // ) //} - for _, arg := range args { - params.r.set( - arg.name, - params.constant(arg.arg), - ) - } + //for _, arg := range args { + // params.r.set( + // arg.name, + // params.constant(arg.arg), + // ) + ////} + //args2 := make([]rideType, len(args)) + //for i := range args { + // args2[i] = args[i].arg + //} f := NewMain(params) for _, node := range nodes { diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index ee2fa0a524..5900c6c84f 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -87,7 +87,7 @@ func Test22(t *testing.T) { require.NoError(t, err, test.comment) assert.NotNil(t, tree, test.comment) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err, test.comment) assert.NotNil(t, script, test.comment) @@ -156,7 +156,7 @@ func TestCallExternal(t *testing.T) { }, } - f, err := compileVerifier(3, n) + f, err := compileFunction("", 3, []Node{n}, nil) require.NoError(t, err) require.Equal(t, @@ -184,7 +184,7 @@ func TestIfConditionRightByteCode(t *testing.T) { }, } - f, err := compileVerifier(3, n) + f, err := compileFunction("", 3, []Node{n}, nil) require.NoError(t, err) require.Equal(t, @@ -229,7 +229,7 @@ func TestDoubleCall(t *testing.T) { }, } - f, err := compileVerifier(3, n) + f, err := compileFunction("", 3, []Node{n}, nil) require.NoError(t, err) require.Equal(t, @@ -269,7 +269,7 @@ func TestCallWithConstArg(t *testing.T) { invocationParameter: "", } - f, err := compileVerifier(3, n) + f, err := compileFunction("", 3, []Node{n}, nil) require.NoError(t, err) bt := []byte{ @@ -322,7 +322,7 @@ func TestMultipleCallConstantFuncArgument(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) @@ -432,7 +432,7 @@ func TestCompileDapp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) @@ -492,7 +492,7 @@ func Test2121(t *testing.T) { t.Log(Decompiler(tree.Verifier)) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) @@ -549,7 +549,7 @@ func TestIfStmt(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) @@ -609,7 +609,7 @@ func Test44(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) @@ -699,7 +699,7 @@ func Test777(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) @@ -752,7 +752,7 @@ func Test888(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) @@ -823,7 +823,7 @@ func TestNoDuplicateCallToState(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier(tree) + script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index e84e6e1c9e..c0d73b2b77 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -2,7 +2,6 @@ package ride import ( "fmt" - "math" ) type arguments []string @@ -43,14 +42,10 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP // all variable we add only visible to current scope, // avoid corrupting parent state. params.r = newReferences(params.r) - for i := range args { - e := params.u.next() - params.r.set(args[i], e) - // set to global - globalScope.set(fmt.Sprintf("%s$%d", name, i), e) - } - // assume that it's verifier + + // Function call: verifier or not. if invokeParam != "" { + args = append([]string{invokeParam}, args...) // tx //pos, ok := params.r.get("tx") //if !ok { @@ -61,7 +56,13 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP //params.b.write(encode(0)) //params.b.writeByte(OpReturn) //params.r.set(invokeParam, pos) - params.r.set(invokeParam, math.MaxUint16) + //params.r.set(invokeParam, params.u.next()) + } + for i := range args { + e := params.u.next() + params.r.set(args[i], e) + // set to global + globalScope.set(fmt.Sprintf("%s$%d", name, i), e) } return &FuncState{ @@ -90,6 +91,14 @@ func (a FuncState) Return() Fsm { // if function has invoke param, it means no other code will be provided. if a.invokeParam != "" { a.b.startPos() + for i := len(a.args) - 1; i >= 0; i-- { + a.b.writeByte(OpCache) + uniq, ok := a.params.r.get(a.args[i]) + if !ok { + panic("function param `" + a.args[i] + "` not found") + } + a.b.write(encode(uniq)) + } a.b.writeByte(OpCall) a.b.write(encode(a.lastStmtOffset)) } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index a76ddddcbd..00c0a220d5 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -3,12 +3,11 @@ package ride type Executable struct { LibVersion int ByteCode []byte - Constants []rideType EntryPoints map[string]uint16 References map[uniqueid]point } -func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { +func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (RideResult, error) { fSelect, err := selectFunctions(a.LibVersion) if err != nil { return nil, err @@ -22,11 +21,11 @@ func (a *Executable) Run(environment RideEnvironment) (RideResult, error) { v := vm{ code: a.ByteCode, ip: int(a.EntryPoints[""]), - constants: a.Constants, functions: mergeWithPredefined(fSelect, predefined), functionName: provider, env: environment, ref: a.References, + stack: arguments, } return v.run() diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 6270a0f3ba..5edd551005 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -19,7 +19,7 @@ func CallVerifier3(txID string, env RideEnvironment, tree *Tree) (RideResult, er if err != nil { return nil, errors.Wrap(err, "call compile script") } - return compiled.Run(env) + return compiled.Run(env, []rideType{env.transaction()}) } func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { @@ -28,13 +28,13 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, err return nil, err } - //r, err := CallVerifier2(env, tree) - //if err != nil { - // return nil, err - //} - //if !r.Eq(r2) { - // return nil, errors.New("R1 != R2: failed to call account script on transaction ") - //} + r2, err := CallVerifier2(env, tree) + if err != nil { + return nil, err + } + if !r.Eq(r2) { + return nil, errors.New("R1 != R2: failed to call account script on transaction ") + } return r, nil } @@ -69,9 +69,26 @@ func CallFunction2(txID string, env RideEnvironment, tree *Tree, name string, ar if name == "" { name = "default" } - f, err := CompileFunction(txID, tree, name, args) + f, numArgs, err := CompileFunction(txID, tree, name, args) if err != nil { return nil, err } - return f.Run(env) + if l := len(args); l != numArgs { + return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) + } + applyArgs := make([]rideType, 0, len(args)+1) + applyArgs = append(applyArgs, env.invocation()) + for _, arg := range args { + a, err := convertArgument(arg) + if err != nil { + return nil, errors.Wrapf(err, "failed to call function '%s'", name) + } + //s.pushValue(function.Arguments[i], a) + applyArgs = append(applyArgs, a) + //namedArgument{ + // name: function.Arguments[i], + // arg: a, + //}) + } + return f.Run(env, applyArgs) } diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index e8d257561d..fa08f156b5 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -79,7 +79,7 @@ func TestSimpleScriptEvaluation(t *testing.T) { require.NoError(t, err, test.comment) assert.NotNil(t, tree, test.comment) - res, err := CallVerifier(test.env, tree) + res, err := CallVerifier("", test.env, tree) require.NoError(t, err, test.comment) require.NotNil(t, res, test.comment) @@ -327,7 +327,7 @@ func TestFunctionsEvaluation(t *testing.T) { require.NoError(t, err, test.name) assert.NotNil(t, tree, test.name) - res, err := CallVerifier(test.env, tree) + res, err := CallVerifier("", test.env, tree) if test.error { assert.Error(t, err, "No error in "+test.name) } else { @@ -357,7 +357,7 @@ func TestOverlapping(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(nil, tree) + res, err := CallVerifier("", nil, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -380,7 +380,7 @@ func TestUserFunctionsInExpression(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(nil, tree) + res, err := CallVerifier("", nil, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -441,7 +441,7 @@ func TestDataFunctions(t *testing.T) { require.NoError(t, err, test.name) assert.NotNil(t, tree, test.name) - res, err := CallVerifier(env, tree) + res, err := CallVerifier("", env, tree) require.NoError(t, err, test.name) r, ok := res.(ScriptResult) require.True(t, ok, test.name) @@ -513,7 +513,7 @@ func TestDappCallable(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "tellme", proto.Arguments{proto.NewStringArgument("abc")}) + res, err := CallFunction("", env, tree, "tellme", proto.Arguments{proto.NewStringArgument("abc")}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -580,7 +580,7 @@ func TestDappDefaultFunc(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "", proto.Arguments{}) + res, err := CallFunction("", env, tree, "", proto.Arguments{}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -644,7 +644,7 @@ func TestDappVerify(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(env, tree) + res, err := CallVerifier("", env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -676,7 +676,7 @@ func TestDappVerifySuccessful(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(env, tree) + res, err := CallVerifier("", env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -705,7 +705,7 @@ func TestTransferSet(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100500)}) + res, err := CallFunction("", env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100500)}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -757,7 +757,7 @@ func TestScriptResult(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100)}) + res, err := CallFunction("", env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100)}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -851,7 +851,7 @@ func TestMatchOverwrite(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(env, tree) + res, err := CallVerifier("", env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -910,7 +910,7 @@ func TestFailSript1(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(env, tree) + res, err := CallVerifier("", env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -1022,7 +1022,7 @@ func TestFailSript2(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(env, tree) + res, err := CallVerifier("", env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -1137,7 +1137,7 @@ func TestWhaleDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "inviteuser", arguments) + res, err := CallFunction("", env, tree, "inviteuser", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1263,7 +1263,7 @@ func TestExchangeDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "cancel", arguments) + res, err := CallFunction("", env, tree, "cancel", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1430,7 +1430,7 @@ func TestBankDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "buyBack", proto.Arguments{}) + res, err := CallFunction("", env, tree, "buyBack", proto.Arguments{}) require.NoError(t, err) _, ok := res.(DAppResult) require.True(t, ok) @@ -1574,7 +1574,7 @@ func TestLigaDApp1(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "stage2", proto.Arguments{}) + res, err := CallFunction("", env, tree, "stage2", proto.Arguments{}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1758,7 +1758,7 @@ func TestLigaDApp1(t *testing.T) { }, } - res, err = CallFunction(env, tree, "stage31", args2) + res, err = CallFunction("", env, tree, "stage31", args2) require.NoError(t, err) r, ok = res.(DAppResult) require.True(t, ok) @@ -1887,7 +1887,7 @@ func TestTestingDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "main", arguments) + res, err := CallFunction("", env, tree, "main", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2000,7 +2000,7 @@ func TestDropElementDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "dropElementInArray", arguments) + res, err := CallFunction("", env, tree, "dropElementInArray", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2114,7 +2114,7 @@ func TestMathDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "coxRossRubinsteinCall", arguments) + res, err := CallFunction("", env, tree, "coxRossRubinsteinCall", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2240,7 +2240,7 @@ func TestDAppWithInvalidAddress(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "deposit", arguments) + res, err := CallFunction("", env, tree, "deposit", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2369,7 +2369,7 @@ func Test8Ball(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "tellme", arguments) + res, err := CallFunction("", env, tree, "tellme", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2477,7 +2477,7 @@ func TestIntegerEntry(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - _, err = CallFunction(env, tree, "tellme", arguments) + _, err = CallFunction("", env, tree, "tellme", arguments) assert.Error(t, err) } @@ -2532,7 +2532,7 @@ func TestAssetInfoV3V4(t *testing.T) { require.NoError(t, err) assert.NotNil(t, treeV3) - res, err := CallVerifier(env, treeV3) + res, err := CallVerifier("", env, treeV3) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -2553,7 +2553,7 @@ func TestAssetInfoV3V4(t *testing.T) { require.NoError(t, err) assert.NotNil(t, treeV3) - res, err = CallVerifier(env, treeV4) + res, err = CallVerifier("", env, treeV4) require.NoError(t, err) r, ok = res.(ScriptResult) require.True(t, ok) @@ -2569,7 +2569,7 @@ func TestJSONParsing(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(nil, tree) + res, err := CallVerifier("", nil, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -2591,7 +2591,7 @@ func TestDAppWithFullIssue(t *testing.T) { return rideBytes(id) }, } - res, err := CallFunction(env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) + res, err := CallFunction("", env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2617,7 +2617,7 @@ func TestDAppWithSimpleIssue(t *testing.T) { return rideBytes(id) }, } - res, err := CallFunction(env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) + res, err := CallFunction("", env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2719,7 +2719,7 @@ func TestBadType(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "initDraw", arguments) + res, err := CallFunction("", env, tree, "initDraw", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 5c56168fc0..6720a92ebb 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -24,10 +24,10 @@ type vm struct { func (m *vm) run() (RideResult, error) { numOperations := 0 - limitOperations := 100000 - if m.stack != nil { - m.stack = m.stack[0:0] - } + limitOperations := 20000 + //if m.stack != nil { + // m.stack = m.stack[0:0] + //} for m.ip < len(m.code) { if numOperations >= limitOperations { @@ -38,16 +38,8 @@ func (m *vm) run() (RideResult, error) { op := m.code[m.ip] m.ip++ switch op { - case OpPush: - m.push(m.constant()) - case OpPop: - _, err := m.pop() - if err != nil { - return nil, errors.Wrap(err, "failed to pop value") - } case OpJump: pos := m.arg16() - m.jmps = append(m.jmps, m.ip) m.ip = pos @@ -82,7 +74,7 @@ func (m *vm) run() (RideResult, error) { } v, err := obj.get(string(p)) if err != nil { - return nil, err + return nil, errors.Wrap(err, "vm OpProperty") } m.push(v) case OpCall: diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index 2b56bb0c24..4245e01d1e 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -125,7 +125,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if r.UserError() != "" { return errors.Errorf("account script on transaction '%s' failed with error: %v", txID, r.UserError()) } - return errs.NewTransactionNotAllowedByScript("script failed", id) + return errors.Wrap(errs.NewTransactionNotAllowedByScript("script failed", id), txID) } // Increase complexity. ev, err := a.state.EstimatorVersion() From 86f928198d74dcfbf08fb813e1ce81eed4a87269 Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 3 Dec 2020 16:39:18 +0300 Subject: [PATCH 15/55] Cache variable result. --- pkg/ride/compiler2_test.go | 41 ++++++++++++++++++---------------- pkg/ride/compiler_assigment.go | 12 ++++++---- pkg/ride/compiler_call_user.go | 1 + pkg/ride/compiler_func.go | 1 + pkg/ride/result.go | 11 +++++++++ pkg/ride/tree_evaluation.go | 26 +++++++++++++++++++-- pkg/ride/tree_evaluator.go | 32 +++++++++++++++++--------- pkg/ride/vm.go | 18 ++++++++++++--- 8 files changed, 103 insertions(+), 39 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 5900c6c84f..42fde280d3 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -91,7 +91,7 @@ func Test22(t *testing.T) { require.NoError(t, err, test.comment) assert.NotNil(t, script, test.comment) - res, err := script.Run(test.env) + res, err := script.Run(test.env, nil) require.NoError(t, err, test.comment) assert.NotNil(t, res, test.comment) r, ok := res.(ScriptResult) @@ -156,7 +156,7 @@ func TestCallExternal(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}, nil) + f, err := compileFunction("", 3, []Node{n}) require.NoError(t, err) require.Equal(t, @@ -184,25 +184,28 @@ func TestIfConditionRightByteCode(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}, nil) + f, err := compileFunction("", 3, []Node{n}) require.NoError(t, err) require.Equal(t, []byte{ OpReturn, - OpRef, 0, 1, - OpJumpIfFalse, 0, 11, 0, 15, 0, 19, OpRef, 0, 2, - OpReturn, + OpJumpIfFalse, 0, 11, 0, 15, 0, 19, OpRef, 0, 3, OpReturn, - OpReturn, OpRef, 0, 4, OpReturn, + + OpCache, 0, 1, + + OpReturn, + OpRef, 0, 1, + OpReturn, }, f.ByteCode) - rs, err := f.Run(nil) + rs, err := f.Run(nil, nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } @@ -229,7 +232,7 @@ func TestDoubleCall(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}, nil) + f, err := compileFunction("", 3, []Node{n}) require.NoError(t, err) require.Equal(t, @@ -247,7 +250,7 @@ func TestDoubleCall(t *testing.T) { require.EqualValues(t, 5, f.EntryPoints[""]) - rs, err := f.Run(nil) + rs, err := f.Run(nil, nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } @@ -269,7 +272,7 @@ func TestCallWithConstArg(t *testing.T) { invocationParameter: "", } - f, err := compileFunction("", 3, []Node{n}, nil) + f, err := compileFunction("", 3, []Node{n}) require.NoError(t, err) bt := []byte{ @@ -290,7 +293,7 @@ func TestCallWithConstArg(t *testing.T) { //f.ByteCode = bt //f.EntryPoints[""] = 4 - rs, err := f.Run(nil) + rs, err := f.Run(nil, nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } @@ -326,7 +329,7 @@ func TestMultipleCallConstantFuncArgument(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - res, err := script.Run(env) + res, err := script.Run(env, nil) require.NoError(t, err) assert.NotNil(t, res) r, ok := res.(ScriptResult) @@ -436,7 +439,7 @@ func TestCompileDapp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - res, err := script.Run(env) + res, err := script.Run(env, nil) require.NoError(t, err) assert.NotNil(t, res) r, ok := res.(ScriptResult) @@ -496,7 +499,7 @@ func Test2121(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - res, err := script.Run(env) + res, err := script.Run(env, nil) require.NoError(t, err) assert.NotNil(t, res) r, ok := res.(ScriptResult) @@ -553,7 +556,7 @@ func TestIfStmt(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - res, err := script.Run(env) + res, err := script.Run(env, nil) require.NoError(t, err) assert.NotNil(t, res) r, ok := res.(ScriptResult) @@ -703,7 +706,7 @@ func Test777(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - res, err := script.Run(env) + res, err := script.Run(env, nil) require.NoError(t, err) assert.NotNil(t, res) r, ok := res.(ScriptResult) @@ -756,7 +759,7 @@ func Test888(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - _, err = script.Run(env) + _, err = script.Run(env, nil) require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"") } @@ -827,6 +830,6 @@ func TestNoDuplicateCallToState(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - _, err = script.Run(env) + _, err = script.Run(env, nil) require.NoError(t, err) } diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index a9c86c0191..288d32a0ee 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -8,6 +8,7 @@ type AssigmentState struct { startedAt uint16 //ret uint16 constant rideType + n uniqueid } func (a AssigmentState) retAssigment(startedAt uint16, endedAt uint16) Fsm { @@ -60,6 +61,7 @@ func newAssigmentFsm(prev Fsm, p params, name string) Fsm { params: p, name: name, startedAt: p.b.len(), + n: p.u.next(), } } @@ -71,15 +73,17 @@ func (a AssigmentState) Assigment(name string) Fsm { } func (a AssigmentState) Return() Fsm { + a.b.writeByte(OpCache) + a.b.write(encode(a.n)) a.b.ret() // store reference on variable and it's offset. - n := a.u.next() + if a.constant != nil { - a.c.set(n, a.constant, nil, 0, a.name) + a.c.set(a.n, a.constant, nil, 0, a.name) } else { - a.c.set(n, nil, nil, a.startedAt, a.name) + a.c.set(a.n, nil, nil, a.startedAt, a.name) } - a.r.set(a.name, n) + a.r.set(a.name, a.n) return a.prev.retAssigment(a.startedAt, a.params.b.len()) } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 7ee3bc3b63..be9cd8eb9f 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -111,6 +111,7 @@ func (a CallUserState) Call(name string, argc uint16) Fsm { a.ret = func(state CallUserState, startedAt uint16, endedAt uint16) { a.b.writeByte(OpCache) a.b.write(encode(n)) + a.b.writeByte(OpPop) } return callTransition(a, a.params, name, argc) } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index c0d73b2b77..9ba56a791e 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -98,6 +98,7 @@ func (a FuncState) Return() Fsm { panic("function param `" + a.args[i] + "` not found") } a.b.write(encode(uniq)) + a.b.writeByte(OpPop) } a.b.writeByte(OpCall) a.b.write(encode(a.lastStmtOffset)) diff --git a/pkg/ride/result.go b/pkg/ride/result.go index 58444abe1f..ff4a6d61ad 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -10,18 +10,24 @@ type RideResult interface { UserError() string ScriptActions() proto.ScriptActions Eq(RideResult) bool + Calls() []callLog } type ScriptResult struct { res bool msg string operations int + calls []callLog } func (r ScriptResult) Result() bool { return r.res } +func (r ScriptResult) Calls() []callLog { + return r.calls +} + func (r ScriptResult) UserError() string { return r.msg } @@ -44,12 +50,17 @@ type DAppResult struct { actions proto.ScriptActions msg string operations int + calls []callLog } func (r DAppResult) Result() bool { return r.res } +func (r DAppResult) Calls() []callLog { + return r.calls +} + func (r DAppResult) UserError() string { return r.msg } diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 5edd551005..44a2745b7f 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -33,6 +33,26 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, err return nil, err } if !r.Eq(r2) { + c1 := r.Calls() + c2 := r2.Calls() + max := len(c1) + if len(c2) > len(c1) { + max = len(c2) + } + for i := 0; i < max; i++ { + zap.S().Error("R1 != R2: failed to call account script on transaction ") + if i <= len(c1)-1 { + zap.S().Error(c1[i]) + } else { + zap.S().Error("") + } + if i <= len(c2)-1 { + zap.S().Error(c2[i]) + } else { + zap.S().Error("") + } + } + return nil, errors.New("R1 != R2: failed to call account script on transaction ") } return r, nil @@ -59,8 +79,10 @@ func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, arg return nil, errors.Wrap(err, "call function by vm") } if !rs1.Eq(rs2) { - zap.S().Errorf("result mismatch tree %+q vm %+q", rs1, rs2) - return nil, errors.New("result mismatch") + zap.S().Errorf("%s, result mismatch", txID) + zap.S().Errorf("tree: %+q", rs1) + zap.S().Errorf("vm : %+q", rs2) + return nil, errors.New(txID + ": result mismatch") } return rs2, nil } diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index a87e7f3835..b9005f5858 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -200,13 +200,18 @@ func selectFunctionNames(v int) ([]string, error) { } } +type callLog struct { + name string + args []rideType + result rideType +} + type treeEvaluator struct { - dapp bool - //limit int - //cost int - f Node - s evaluationScope - env RideEnvironment + dapp bool + f Node + s evaluationScope + env RideEnvironment + calls []callLog } func (e *treeEvaluator) evaluate() (RideResult, error) { @@ -217,17 +222,17 @@ func (e *treeEvaluator) evaluate() (RideResult, error) { switch res := r.(type) { case rideThrow: if e.dapp { - return DAppResult{res: false, msg: string(res)}, nil + return DAppResult{res: false, msg: string(res), calls: e.calls}, nil } - return ScriptResult{res: false, msg: string(res)}, nil + return ScriptResult{res: false, msg: string(res), calls: e.calls}, nil case rideBoolean: - return ScriptResult{res: bool(res)}, nil + return ScriptResult{res: bool(res), calls: e.calls}, nil case rideObject: actions, err := objectToActions(e.env, res) if err != nil { return nil, errors.Wrap(err, "failed to convert evaluation result") } - return DAppResult{res: true, actions: actions, msg: ""}, nil + return DAppResult{res: true, actions: actions, msg: "", calls: e.calls}, nil case rideList: actions := make([]proto.ScriptAction, len(res)) for i, item := range res { @@ -237,7 +242,7 @@ func (e *treeEvaluator) evaluate() (RideResult, error) { } actions[i] = a } - return DAppResult{res: true, actions: actions}, nil + return DAppResult{res: true, actions: actions, calls: e.calls}, nil default: return nil, errors.Errorf("unexpected result type '%T'", r) } @@ -349,6 +354,11 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { args[i] = a } r, err := f(e.env, args...) + e.calls = append(e.calls, callLog{ + name: id, + args: args, + result: r, + }) if err != nil { return nil, errors.Wrapf(err, "failed to call system function '%s'", id) } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 6720a92ebb..14f4eb69a5 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -20,6 +20,7 @@ type vm struct { jmps []int ref map[uint16]point cache bool + calls []callLog } func (m *vm) run() (RideResult, error) { @@ -38,6 +39,11 @@ func (m *vm) run() (RideResult, error) { op := m.code[m.ip] m.ip++ switch op { + case OpPop: + _, err := m.pop() + if err != nil { + return nil, err + } case OpJump: pos := m.arg16() m.jmps = append(m.jmps, m.ip) @@ -99,6 +105,11 @@ func (m *vm) run() (RideResult, error) { return nil, errors.Errorf("external function '%s' not implemented", m.functionName(id)) } res, err := fn(m.env, in...) + m.calls = append(m.calls, callLog{ + name: m.functionName(id), + args: in, + result: res, + }) if err != nil { return nil, errors.Wrapf(err, "iteration %d", numOperations) } @@ -116,13 +127,13 @@ func (m *vm) run() (RideResult, error) { } switch tv := v.(type) { case rideBoolean: - return ScriptResult{res: bool(tv), operations: numOperations}, nil + return ScriptResult{res: bool(tv), operations: numOperations, calls: m.calls}, nil case rideObject: actions, err := objectToActions(m.env, tv) if err != nil { return nil, errors.Wrap(err, "failed to convert evaluation result") } - return DAppResult{res: true, actions: actions, msg: ""}, nil + return DAppResult{res: true, actions: actions, msg: "", calls: m.calls}, nil case rideList: actions := make([]proto.ScriptAction, len(tv)) for i, item := range tv { @@ -132,7 +143,7 @@ func (m *vm) run() (RideResult, error) { } actions[i] = a } - return DAppResult{res: true, actions: actions}, nil + return DAppResult{res: true, actions: actions, calls: m.calls}, nil default: return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) } @@ -154,6 +165,7 @@ func (m *vm) run() (RideResult, error) { if err != nil { return nil, errors.Wrap(err, "no value to cache") } + m.push(value) m.ref[refID] = point{ value: value, } From f6a69e9e4d3a5fc01c8ef7a26502c4930367cffa Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 3 Dec 2020 19:26:00 +0300 Subject: [PATCH 16/55] Clear cache. --- pkg/ride/compiler2_test.go | 41 ++++++++++++++++++++++++++++++++ pkg/ride/compiler_assigment.go | 36 ++++++++++++++++++---------- pkg/ride/compiler_call_system.go | 3 ++- pkg/ride/compiler_call_user.go | 5 ++-- pkg/ride/compiler_conditional.go | 12 ++++++++-- pkg/ride/compiler_func.go | 17 +++++++++++-- pkg/ride/compiler_helpers.go | 4 +++- pkg/ride/compiler_main.go | 10 +++++++- pkg/ride/compiler_state.go | 4 ++-- pkg/ride/decompiler.go | 5 ++++ pkg/ride/functions_predefined.go | 7 +++++- pkg/ride/functions_proto_test.go | 13 ++++++++++ pkg/ride/opcodes.go | 5 ++-- pkg/ride/vm.go | 11 +++++++++ 14 files changed, 146 insertions(+), 27 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 42fde280d3..9ebe68655f 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -201,6 +201,7 @@ func TestIfConditionRightByteCode(t *testing.T) { OpReturn, OpRef, 0, 1, + OpClearCache, 0, 1, OpReturn, }, f.ByteCode) @@ -255,6 +256,46 @@ func TestDoubleCall(t *testing.T) { require.Equal(t, true, rs.Result()) } +/* +func abc() { + let x = 5 + let y = 6 + x +} +*/ +func TestClearInternalVariables(t *testing.T) { + n := &FunctionDeclarationNode{ + Name: "abc", + Arguments: nil, + Body: &AssignmentNode{ + Name: "x", + Expression: &LongNode{Value: 5}, + Block: &AssignmentNode{ + Name: "y", + Expression: &LongNode{Value: 6}, + Block: &ReferenceNode{ + Name: "x", + }, + }, + }, + } + + f, err := compileFunction("", 3, []Node{n}) + require.NoError(t, err) + + require.Equal(t, + []byte{ + OpReturn, + OpRef, 0, 1, + OpClearCache, 0, 2, + OpClearCache, 0, 1, + OpReturn, + + OpReturn, + }, + f.ByteCode) +} + // func id(v: Boolean) = v; id(true) func TestCallWithConstArg(t *testing.T) { n := &FunctionDeclarationNode{ diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 288d32a0ee..577f5ebc61 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -8,7 +8,11 @@ type AssigmentState struct { startedAt uint16 //ret uint16 constant rideType - n uniqueid + // ref id + n uniqueid + + // Clean internal assigments. + assigments []uniqueid } func (a AssigmentState) retAssigment(startedAt uint16, endedAt uint16) Fsm { @@ -51,17 +55,17 @@ func (a AssigmentState) Boolean(v bool) Fsm { return a } -func assigmentFsmTransition(prev Fsm, params params, name string) Fsm { - return newAssigmentFsm(prev, params, name) +func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid) Fsm { + return newAssigmentFsm(prev, params, name, n) } -func newAssigmentFsm(prev Fsm, p params, name string) Fsm { +func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid) Fsm { return AssigmentState{ prev: prev, params: p, name: name, startedAt: p.b.len(), - n: p.u.next(), + n: n, } } @@ -69,19 +73,25 @@ func newAssigmentFsm(prev Fsm, p params, name string) Fsm { func (a AssigmentState) Assigment(name string) Fsm { params := a.params params.r = newReferences(params.r) - return assigmentFsmTransition(a, params, name) + // TODO clear var in var + n := a.params.u.next() + a.assigments = append(a.assigments, n) + return assigmentFsmTransition(a, params, name, params.u.next()) } func (a AssigmentState) Return() Fsm { - a.b.writeByte(OpCache) - a.b.write(encode(a.n)) - a.b.ret() - // store reference on variable and it's offset. - + for i := len(a.assigments) - 1; i >= 0; i-- { + a.b.writeByte(OpClearCache) + a.b.write(encode(a.assigments[i])) + } + // constant if a.constant != nil { - a.c.set(a.n, a.constant, nil, 0, a.name) + a.c.set(a.n, a.constant, nil, 0, true, a.name) } else { - a.c.set(a.n, nil, nil, a.startedAt, a.name) + a.c.set(a.n, nil, nil, a.startedAt, false, a.name) + a.b.writeByte(OpCache) + a.b.write(encode(a.n)) + a.b.ret() } a.r.set(a.name, a.n) return a.prev.retAssigment(a.startedAt, a.params.b.len()) diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index e0042eb441..82c01ce829 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -70,7 +70,8 @@ func newCallSystemFsm(prev Fsm, params params, name string, argc uint16) Fsm { } func (a CallSystemState) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) + //return assigmentFsmTransition(a, a.params, name) + panic("illegal transition") } func (a CallSystemState) Long(value int64) Fsm { diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index be9cd8eb9f..538ed7dfb6 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -68,7 +68,8 @@ func (a CallUserState) Boolean(v bool) Fsm { } func (a CallUserState) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) + //return assigmentFsmTransition(a, a.params, name) + panic("illegal transition") } func (a CallUserState) Long(value int64) Fsm { @@ -103,7 +104,7 @@ func (a CallUserState) Return() Fsm { func (a CallUserState) Call(name string, argc uint16) Fsm { n := a.u.next() - a.c.set(n, nil, nil, 0, fmt.Sprintf("function as paramentr: %s$%d", name, n)) + a.c.set(n, nil, nil, 0, false, fmt.Sprintf("function as paramentr: %s$%d", name, n)) a.argn = append(a.argn, n) if a.ret != nil { panic("already assigned") diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index c11dbee5de..1ac63228e7 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -28,10 +28,12 @@ type ConditionalState struct { trueStartedAt uint16 falseStartedAt uint16 rets []uint16 + + // Clean assigments after exit. + assigments []uniqueid } func (a ConditionalState) retAssigment(startedAt uint16, endedAt uint16) Fsm { - //a.retAssig = pos return a } @@ -75,10 +77,16 @@ func (a ConditionalState) FalseBranch() Fsm { } func (a ConditionalState) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) + n := a.params.u.next() + a.assigments = append(a.assigments, n) + return assigmentFsmTransition(a, a.params, name, n) } func (a ConditionalState) Return() Fsm { + for i := len(a.assigments) - 1; i >= 0; i-- { + a.b.writeByte(OpClearCache) + a.b.write(encode(a.assigments[i])) + } a.b.ret() a.b.patch(a.patchTruePosition, encode(a.rets[1])) a.b.patch(a.patchFalsePosition, encode(a.rets[2])) diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 9ba56a791e..5f2339e072 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -24,6 +24,10 @@ type FuncState struct { invokeParam string lastStmtOffset uint16 startedAt uint16 + + // References that defined inside function. + // Should be cleared before exit. + assigments []uniqueid } func (a FuncState) retAssigment(startedAt uint16, endedAt uint16) Fsm { @@ -78,14 +82,23 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP } func (a FuncState) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) + n := a.params.u.next() + a.assigments = append(a.assigments, n) + return assigmentFsmTransition(a, a.params, name, n) } func (a FuncState) Return() Fsm { funcID := a.params.u.next() a.globalScope.set(a.name, funcID) - a.params.c.set(funcID, nil, nil, a.lastStmtOffset, a.name) + a.params.c.set(funcID, nil, nil, a.lastStmtOffset, false, a.name) // TODO clean args + + // Clean internal assigments. + for i := len(a.assigments) - 1; i >= 0; i-- { + a.b.writeByte(OpClearCache) + a.b.write(encode(a.assigments[i])) + } + a.b.ret() // if function has invoke param, it means no other code will be provided. diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 0eb52a3cd6..65e8257faf 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -96,6 +96,7 @@ type point struct { position uint16 value rideType fn rideFunction + constant bool debugInfo string } @@ -109,11 +110,12 @@ func newCell() *cell { } } -func (a *cell) set(u uniqueid, result rideType, fn rideFunction, position uint16, debug string) { +func (a *cell) set(u uniqueid, result rideType, fn rideFunction, position uint16, constant bool, debug string) { a.values[u] = point{ position: position, value: result, fn: fn, + constant: constant, debugInfo: debug, } } diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index dee442d467..332720273e 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -4,6 +4,8 @@ package ride type MainState struct { params retAssig uint16 + + assigments []uniqueid } func (a MainState) retAssigment(startedAt uint16, endedAt uint16) Fsm { @@ -51,10 +53,16 @@ func NewMain(params params) Fsm { } func (a MainState) Assigment(name string) Fsm { - return assigmentFsmTransition(a, a.params, name) + n := a.params.u.next() + a.assigments = append(a.assigments, n) + return assigmentFsmTransition(a, a.params, name, n) } func (a MainState) Return() Fsm { + for i := len(a.assigments) - 1; i >= 0; i-- { + a.b.writeByte(OpClearCache) + a.b.write(encode(a.assigments[i])) + } a.b.ret() return a } diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 3a1262d9ad..78a00b0ed5 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -51,12 +51,12 @@ type params struct { func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) { a.r.set(name, id) - a.c.set(id, nil, fn, 0, name) + a.c.set(id, nil, fn, 0, false, name) } func (a *params) constant(value rideType) uniqueid { n := a.u.next() - a.c.set(n, value, nil, 0, fmt.Sprintf("constant %q", value)) + a.c.set(n, value, nil, 0, false, fmt.Sprintf("constant %q", value)) return n } diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index 25f9b239a2..25348de00d 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -3,6 +3,8 @@ package ride import ( "fmt" "strings" + + "github.com/mr-tron/base58" ) type detreeType = func(s *strings.Builder, tree Node) @@ -115,6 +117,9 @@ func detree(s *strings.Builder, tree Node) { s.WriteString(fmt.Sprintf("%t", n.Value)) case *LongNode: s.WriteString(fmt.Sprintf("%d", n.Value)) + case *BytesNode: + s.WriteString("b58:") + s.WriteString(base58.Encode(n.Value)) case nil: // nothing default: diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index 3966f2ee3d..d883f071d1 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -27,7 +27,12 @@ func height(env RideEnvironment, _ ...rideType) (rideType, error) { } func nilFunc(env RideEnvironment, _ ...rideType) (rideType, error) { - return rideList{}, nil + var out rideList = nil + return out, nil +} + +func retRideType() rideList { + return nil } var predefinedFunctions = map[string]predefFunc{ diff --git a/pkg/ride/functions_proto_test.go b/pkg/ride/functions_proto_test.go index 9c452cdc4c..2a861c96eb 100644 --- a/pkg/ride/functions_proto_test.go +++ b/pkg/ride/functions_proto_test.go @@ -117,6 +117,19 @@ func TestAddressFromRecipient(t *testing.T) { t.SkipNow() } +func TestWriteSet(t *testing.T) { + _, err := writeSet(nil, nil) + require.Error(t, err) + + _, err = writeSet(nil, rideList{}) + require.NoError(t, err) + + var lst rideList = nil + _, err = writeSet(nil, lst) + require.NoError(t, err) + +} + func TestSigVerify(t *testing.T) { msg, err := hex.DecodeString("135212a9cf00d0a05220be7323bfa4a5ba7fc5465514007702121a9c92e46bd473062f00841af83cb7bc4b2cd58dc4d5b151244cc8293e795796835ed36822c6e09893ec991b38ada4b21a06e691afa887db4e9d7b1d2afc65ba8d2f5e6926ff53d2d44d55fa095f3fad62545c714f0f3f59e4bfe91af8") require.NoError(t, err) diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index 2d8863c92c..4d611b4374 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -16,8 +16,9 @@ const ( OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. OpSetArg //11 0xb - FROM (global) -> TO (local): Set value into cell. Two parameters: constant id and cell id. - OpCache //12 0xd - Put constant on stack. One parameter: constant ID. - OpRef //14 0xe = ref id + OpCache //12 0xc - Put constant on stack. One parameter: constant ID. + OpRef //14 0xd = ref id + OpClearCache //15 0xe = ref id // odd, will be removed. OpGlobal diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 14f4eb69a5..43ce174630 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -169,6 +169,17 @@ func (m *vm) run() (RideResult, error) { m.ref[refID] = point{ value: value, } + case OpClearCache: + refID := m.uint16() + point, ok := m.ref[refID] + if !ok { + return nil, errors.Errorf("OpClearCache: no ref with id %d", refID) + } + // Clear cache only if its not constant. + if !point.constant { + point.value = nil + m.ref[refID] = point + } case OpRef: refID := m.uint16() From 0fd9f97e5661d6011c7b66a6d9d7a2f3a679f4cc Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 8 Dec 2020 01:37:41 +0300 Subject: [PATCH 17/55] Fix clear cache. --- pkg/ride/code_samples.go | 13 ++++ pkg/ride/compiler.go | 4 +- pkg/ride/compiler2.go | 2 + pkg/ride/compiler2_test.go | 116 +++++++++++++++++++++++++------ pkg/ride/compiler_conditional.go | 6 +- pkg/ride/compiler_func.go | 6 ++ pkg/ride/compiler_helpers.go | 12 ++-- pkg/ride/compiler_state.go | 4 +- pkg/ride/decompiler.go | 27 ++++++- pkg/ride/serializer.go | 50 +++++++++++++ pkg/ride/tree_evaluation.go | 30 ++++---- pkg/ride/vm.go | 10 +-- pkg/state/scripts_storage.go | 2 - 13 files changed, 227 insertions(+), 55 deletions(-) create mode 100644 pkg/ride/code_samples.go create mode 100644 pkg/ride/serializer.go diff --git a/pkg/ride/code_samples.go b/pkg/ride/code_samples.go new file mode 100644 index 0000000000..9b37602077 --- /dev/null +++ b/pkg/ride/code_samples.go @@ -0,0 +1,13 @@ +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` diff --git a/pkg/ride/compiler.go b/pkg/ride/compiler.go index 7500f168d7..7654bb75b7 100644 --- a/pkg/ride/compiler.go +++ b/pkg/ride/compiler.go @@ -242,7 +242,7 @@ func (c *compiler) conditionalNode(bb *bytes.Buffer, node *ConditionalNode) erro end := bb.Len() bb.Write([]byte{0xff, 0xff}) - // Patch jump to alternative branch + // Patch ref to alternative branch code := bb.Bytes() binary.BigEndian.PutUint16(code[otherwise:], uint16(bb.Len())) @@ -253,7 +253,7 @@ func (c *compiler) conditionalNode(bb *bytes.Buffer, node *ConditionalNode) erro return err } - // Patch jump to the end of alternative branch + // Patch ref to the end of alternative branch code = bb.Bytes() binary.BigEndian.PutUint16(code[end:], uint16(bb.Len())) diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index ecbe477d5f..f6d13119a9 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -3,6 +3,7 @@ package ride import ( "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" + "go.uber.org/zap" ) func ccc(f Fsm, node Node) (Fsm, error) { @@ -236,6 +237,7 @@ func compileFunction(txID string, libVersion int, nodes []Node) (*Executable, er f := NewMain(params) for _, node := range nodes { + zap.S().Error(Decompiler(node)) f, err = ccc(f, node) if err != nil { return nil, err diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 9ebe68655f..b674fd1b59 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -4,8 +4,10 @@ import ( "bytes" "encoding/base64" "errors" + "strconv" "testing" + //"github.com/fxamacker/cbor/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/proto" @@ -22,6 +24,15 @@ func Test22(t *testing.T) { t.Log("key: ", key) return nil, errors.New("not found") }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, } env := &MockRideEnvironment{ transactionFunc: testTransferObject, @@ -69,6 +80,7 @@ func Test22(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}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, @@ -806,41 +818,64 @@ func Test888(t *testing.T) { /* -{-# STDLIB_VERSION 4 #-} -{-# CONTENT_TYPE EXPRESSION #-} +{-# STDLIB_VERSION 3 #-} {-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} -func f() = { - getIntegerValue(this, "1") +func getStringByAddressAndKey(address: Address, key: String) = match getString(address, key) { + case a: String => + a + case _ => + "" } -func f2(value: Int) = { - value == value +func getStringByKey(key: String) = match getString(this, key) { + case a: String => + a + case _ => + "" } -f2(f()) +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) { - source := `BAoBAAAAAWYAAAAACQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAAR0aGlzAgAAAAExCgEAAAACZjIAAAABAAAABXZhbHVlCQAAAAAAAAIFAAAABXZhbHVlBQAAAAV2YWx1ZQkBAAAAAmYyAAAAAQkBAAAAAWYAAAAAjuqz7g==` - - alreadyCalled := false + 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") + //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": + return &proto.StringDataEntry{Value: "3MVHscMp4C3JjeaEiZB6fxeomPZdYEHyamY"}, nil + case "last_confirm_tx": + return &proto.StringDataEntry{Value: "3M9uzVzrAAYEKSHXzKaPhw7iQjwDi9BRJysHZHpbqXJm"}, nil + case "control_contract": + return &proto.StringDataEntry{Value: "3MQdbE6dK59FHxh5rf4biQdyXhdEf3L1R5W"}, nil + } + panic(key) }, RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { - if alreadyCalled { - panic("duplicate call") + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err } - alreadyCalled = true return &proto.IntegerDataEntry{ - Value: 0, + Value: v, }, nil }, } @@ -850,10 +885,11 @@ func TestNoDuplicateCallToState(t *testing.T) { return state }, schemeFunc: func() byte { - return 'T' + return 'S' }, thisFunc: func() rideType { - return rideAddress{} + b := [26]byte{1, 83, 122, 149, 83, 66, 227, 147, 59, 198, 33, 214, 105, 255, 17, 4, 168, 100, 213, 112, 143, 31, 192, 98, 166, 126} + return rideAddress(b) }, heightFunc: func() rideInt { return 1 @@ -871,6 +907,46 @@ func TestNoDuplicateCallToState(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - _, err = script.Run(env, nil) + rs, err := script.Run(env, []rideType{env.transaction()}) + for _, c := range rs.Calls() { + t.Log(c) + } + //t.Log(rs.Calls()) require.NoError(t, err) + + //t.Log(rs.Calls()) + require.False(t, rs.Result()) } + +//type points struct { +// value []point `cbor:"0,keyasint"` +//} + +//func TestSerialize(t *testing.T) { +// +// //m := points{ +// // value: []point{ +// // {value: rideBoolean(true)}, +// // {value: rideInt(5), constant: true}, +// // }, +// //} +// m := point{ +// position: 43, +// value: rideUnit{}, +// fn: nil, +// constant: true, +// debugInfo: "bla", +// } +// +// rs, err := cbor.Marshal(m) +// require.NoError(t, err) +// +// t.Log(rs) +// +// var m2 point +// +// err = cbor.Unmarshal(rs, &m2) +// require.NoError(t, err) +// t.Log(m2) +// +//} diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 1ac63228e7..24d6391d32 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -83,14 +83,16 @@ func (a ConditionalState) Assigment(name string) Fsm { } func (a ConditionalState) Return() Fsm { + a.b.ret() // return for false branch + endPos := a.b.len() for i := len(a.assigments) - 1; i >= 0; i-- { a.b.writeByte(OpClearCache) a.b.write(encode(a.assigments[i])) } - a.b.ret() + a.b.patch(a.patchTruePosition, encode(a.rets[1])) a.b.patch(a.patchFalsePosition, encode(a.rets[2])) - a.b.patch(a.patchNextPosition, encode(a.b.len())) + a.b.patch(a.patchNextPosition, encode(endPos)) return a.prev.retAssigment(a.startedAt, a.b.len()) } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 5f2339e072..1b50ce335a 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -62,12 +62,17 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP //params.r.set(invokeParam, pos) //params.r.set(invokeParam, params.u.next()) } + //assigments := []uniqueid{} for i := range args { e := params.u.next() + //assigments = append(assigments, e) params.r.set(args[i], e) // set to global globalScope.set(fmt.Sprintf("%s$%d", name, i), e) } + //if invokeParam != "" { + // assigments = assigments[1:] + //} return &FuncState{ prev: prev, @@ -78,6 +83,7 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP globalScope: globalScope, invokeParam: invokeParam, startedAt: startedAt, + //assigments: assigments, } } diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 65e8257faf..cebb94187e 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -44,7 +44,7 @@ func (b *builder) ret() { b.w.WriteByte(OpReturn) } -func (b *builder) jump(uint162 uint16) { +func (b *builder) ref(uint162 uint16) { b.w.WriteByte(OpRef) b.w.Write(encode(uint162)) } @@ -93,11 +93,11 @@ func (b *builder) write(i []byte) { } type point struct { - position uint16 - value rideType - fn rideFunction - constant bool - debugInfo string + position uint16 `cbor:"0,keyasint"` + value rideType `cbor:"1,keyasint"` + fn rideFunction `cbor:"-"` + constant bool `cbor:"2,keyasint"` + debugInfo string `cbor:"3,keyasint"` } type cell struct { diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 78a00b0ed5..bdedaa19c8 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -56,7 +56,7 @@ func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) { func (a *params) constant(value rideType) uniqueid { n := a.u.next() - a.c.set(n, value, nil, 0, false, fmt.Sprintf("constant %q", value)) + a.c.set(n, value, nil, 0, true, fmt.Sprintf("constant %q", value)) return n } @@ -96,6 +96,6 @@ func reference(f Fsm, params params, name string) Fsm { panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) } //params.b - params.b.jump(pos) + params.b.ref(pos) return f } diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index 25348de00d..b85310fad9 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -43,9 +43,30 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "101": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, "-", nodes, f) }, + "104": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "*", nodes, f) + }, + "105": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "/", nodes, f) + }, + "300": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "+", nodes, f) + }, "1": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "instanceOf", nodes, f) }, + "401": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "getList", nodes, f) + }, + "420": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "toString", nodes, f) + }, + "600": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "toBase58String", nodes, f) + }, + "2": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "throw", nodes, f) + }, "1052": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "getBinary", nodes, f) }, @@ -57,9 +78,11 @@ func defunc(s *strings.Builder, name string, nodes []Node, f detreeType) { } else { s.WriteString(name) s.WriteString("(") - for _, a := range nodes { + for i, a := range nodes { detree(s, a) - s.WriteString(",") + if len(nodes)-1 != i { + s.WriteString(",") + } } s.WriteString(")") } diff --git a/pkg/ride/serializer.go b/pkg/ride/serializer.go new file mode 100644 index 0000000000..09f652a737 --- /dev/null +++ b/pkg/ride/serializer.go @@ -0,0 +1,50 @@ +package ride + +import ( + "bytes" + "encoding/binary" +) + +const ( + s0 byte = iota + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + strue + sfalse + sint + suint16 + sbytes + sstring + spoint +) + +type Serializer struct { + b bytes.Buffer +} + +func (a *Serializer) Int(v rideInt) { + if v >= 0 && v <= 9 { + a.b.WriteByte(byte(v)) + return + } + a.b.WriteByte(sint) + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(v)) + a.b.Write(b) +} + +func (a *Serializer) Uint16(v uint16) { + a.Int(rideInt(v)) +} + +func (a *Serializer) Point(p point) { + a.b.WriteByte(spoint) + a.Uint16(p.position) +} diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 44a2745b7f..53ec250adf 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -40,16 +40,16 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, err max = len(c2) } for i := 0; i < max; i++ { - zap.S().Error("R1 != R2: failed to call account script on transaction ") + //zap.S().Error("R1 != R2: failed to call account script on transaction ") if i <= len(c1)-1 { - zap.S().Error(c1[i]) + zap.S().Error(i, " ", c1[i]) } else { - zap.S().Error("") + zap.S().Error(i, " ", "") } if i <= len(c2)-1 { - zap.S().Error(c2[i]) + zap.S().Error(i, " ", c2[i]) } else { - zap.S().Error("") + zap.S().Error(i, " ", "") } } @@ -70,20 +70,20 @@ func CallFunction3(env RideEnvironment, tree *Tree, name string, args proto.Argu } func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - rs1, err := CallFunction3(env, tree, name, args) - if err != nil { - return nil, errors.Wrap(err, "call function by tree") - } + //rs1, err := CallFunction3(env, tree, name, args) + //if err != nil { + // return nil, errors.Wrap(err, "call function by tree") + //} rs2, err := CallFunction2(txID, env, tree, name, args) if err != nil { return nil, errors.Wrap(err, "call function by vm") } - if !rs1.Eq(rs2) { - zap.S().Errorf("%s, result mismatch", txID) - zap.S().Errorf("tree: %+q", rs1) - zap.S().Errorf("vm : %+q", rs2) - return nil, errors.New(txID + ": result mismatch") - } + //if !rs1.Eq(rs2) { + // zap.S().Errorf("%s, result mismatch", txID) + // zap.S().Errorf("tree: %+q", rs1) + // zap.S().Errorf("vm : %+q", rs2) + // return nil, errors.New(txID + ": result mismatch") + //} return rs2, nil } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 43ce174630..db57396fc2 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -114,7 +114,9 @@ func (m *vm) run() (RideResult, error) { return nil, errors.Wrapf(err, "iteration %d", numOperations) } if isThrow(res) { - return nil, errors.Errorf("terminated execution by throw with message %q", res) + return ScriptResult{ + calls: m.calls, + }, errors.Errorf("terminated execution by throw with message %q on iteration %d", res, numOperations) } m.push(res) case OpReturn: @@ -166,9 +168,9 @@ func (m *vm) run() (RideResult, error) { return nil, errors.Wrap(err, "no value to cache") } m.push(value) - m.ref[refID] = point{ - value: value, - } + point := m.ref[refID] + point.value = value + m.ref[refID] = point case OpClearCache: refID := m.uint16() point, ok := m.ref[refID] diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index da1baa0c9d..49b382208f 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -8,7 +8,6 @@ import ( "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/ride" - "go.uber.org/zap" ) const ( @@ -19,7 +18,6 @@ const ( ) func scriptBytesToTree(script proto.Script) (*ride.Tree, error) { - zap.S().Error("script: ", script) tree, err := ride.Parse(script) if err != nil { return nil, err From 219cf08035866e662f1679c99679b3da4bf59a10 Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 8 Dec 2020 02:27:09 +0300 Subject: [PATCH 18/55] Reverse assigments. --- pkg/ride/compiler2_test.go | 36 +++++++++++------------ pkg/ride/compiler_assigment.go | 50 ++++++++++++++++++++++---------- pkg/ride/compiler_call_system.go | 7 +++-- pkg/ride/compiler_call_user.go | 15 +++++----- pkg/ride/compiler_conditional.go | 22 ++++++++++---- pkg/ride/compiler_func.go | 12 ++++---- pkg/ride/compiler_main.go | 16 ++++++---- pkg/ride/compiler_property.go | 6 ++-- pkg/ride/compiler_state.go | 2 +- 9 files changed, 103 insertions(+), 63 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index b674fd1b59..6ce8e9cc3a 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -52,22 +52,22 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - {`V1: true`, "AQa3b8tH", nil, true}, - {`V1: false`, `AQfeYll6`, nil, false}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, - {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - {`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", env, false}, - {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, - {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, - {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, - {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, + //{`V1: true`, "AQa3b8tH", nil, true}, + //{`V1: false`, `AQfeYll6`, nil, false}, + //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", env, false}, + //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, + //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, + //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + //{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, + //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + //{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, @@ -76,11 +76,11 @@ func Test22(t *testing.T) { {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - + // {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - {fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, + //{fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 577f5ebc61..280364a9fb 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -3,9 +3,9 @@ package ride // Assigment: let x = 5 type AssigmentState struct { params - prev Fsm - name string - startedAt uint16 + prev Fsm + name string + //startedAt uint16 //ret uint16 constant rideType // ref id @@ -15,8 +15,9 @@ type AssigmentState struct { assigments []uniqueid } -func (a AssigmentState) retAssigment(startedAt uint16, endedAt uint16) Fsm { +func (a AssigmentState) retAssigment(state AssigmentState) Fsm { //a.ret = pos + panic("assig in assig") return a } @@ -61,11 +62,11 @@ func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid) Fs func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid) Fsm { return AssigmentState{ - prev: prev, - params: p, - name: name, - startedAt: p.b.len(), - n: n, + prev: prev, + params: p, + name: name, + //startedAt: p.b.len(), + n: n, } } @@ -80,21 +81,40 @@ func (a AssigmentState) Assigment(name string) Fsm { } func (a AssigmentState) Return() Fsm { - for i := len(a.assigments) - 1; i >= 0; i-- { - a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i])) - } + //for i := len(a.assigments) - 1; i >= 0; i-- { + // a.b.writeByte(OpClearCache) + // a.b.write(encode(a.assigments[i])) + //} + //// constant + //if a.constant != nil { + // a.c.set(a.n, a.constant, nil, 0, true, a.name) + //} else { + // a.c.set(a.n, nil, nil, a.startedAt, false, a.name) + // a.b.writeByte(OpCache) + // a.b.write(encode(a.n)) + // a.b.ret() + //} + //a.r.set(a.name, a.n) + //return a.prev.retAssigment(a.startedAt, a.params.b.len()) + return a.prev.retAssigment(a) +} + +func (a AssigmentState) Write() { + //for i := len(a.assigments) - 1; i >= 0; i-- { + // a.b.writeByte(OpClearCache) + // a.b.write(encode(a.assigments[i])) + //} // constant if a.constant != nil { a.c.set(a.n, a.constant, nil, 0, true, a.name) } else { - a.c.set(a.n, nil, nil, a.startedAt, false, a.name) + a.c.set(a.n, nil, nil, a.b.len(), false, a.name) a.b.writeByte(OpCache) a.b.write(encode(a.n)) a.b.ret() } a.r.set(a.name, a.n) - return a.prev.retAssigment(a.startedAt, a.params.b.len()) + return //a.prev.retAssigment(a.startedAt, a.params.b.len()) } func (a AssigmentState) Long(value int64) Fsm { diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 82c01ce829..ab1495948a 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -15,9 +15,10 @@ type CallSystemState struct { //retAssig uint16 } -func (a CallSystemState) retAssigment(startedAt uint16, endedAt uint16) Fsm { +func (a CallSystemState) retAssigment(_ AssigmentState) Fsm { //a.retAssig = pos - return a + panic("CallSystemState retAssigment") + //return a } func (a CallSystemState) Property(name string) Fsm { @@ -85,7 +86,7 @@ func (a CallSystemState) Return() Fsm { panic(fmt.Sprintf("system function named `%s` not found", a.name)) } a.b.externalCall(n, a.argc) - return a.prev.retAssigment(a.startedAt, a.b.len()) + return a.prev } func (a CallSystemState) Call(name string, argc uint16) Fsm { diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 538ed7dfb6..c940ad66dc 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -14,12 +14,13 @@ type CallUserState struct { startedAt uint16 } -func (a CallUserState) retAssigment(startedAt uint16, endedAt uint16) Fsm { - if a.ret != nil { - a.ret(a, startedAt, endedAt) - } - a.ret = nil - return a +func (a CallUserState) retAssigment(state AssigmentState) Fsm { + panic("CallUserState retAssigment") + //if a.ret != nil { + // a.ret(a, startedAt, endedAt) + //} + //a.ret = nil + //return a } func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { @@ -99,7 +100,7 @@ func (a CallUserState) Return() Fsm { } a.b.call(point.position, a.argc) - return a.prev.retAssigment(a.startedAt, a.b.len()) + return a.prev //.retAssigment(a.startedAt, a.b.len()) } func (a CallUserState) Call(name string, argc uint16) Fsm { diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 24d6391d32..3a029beb90 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -30,10 +30,14 @@ type ConditionalState struct { rets []uint16 // Clean assigments after exit. - assigments []uniqueid + assigments []AssigmentState + //assigmentIndex int } -func (a ConditionalState) retAssigment(startedAt uint16, endedAt uint16) Fsm { +func (a ConditionalState) retAssigment(v AssigmentState) Fsm { + //panic("ConditionalState retAssigment") + //return a + a.assigments = append(a.assigments, v) return a } @@ -55,6 +59,8 @@ func conditionalTransition(prev Fsm, params params) Fsm { prev: prev, params: params, startedAt: params.b.len(), + //assigments: make([][]AssigmentState, 3), + //assigmentIndex: 0, } } @@ -78,22 +84,28 @@ func (a ConditionalState) FalseBranch() Fsm { func (a ConditionalState) Assigment(name string) Fsm { n := a.params.u.next() - a.assigments = append(a.assigments, n) + //a.assigments = append(a.assigments, n) + a.r.set(name, n) return assigmentFsmTransition(a, a.params, name, n) } func (a ConditionalState) Return() Fsm { a.b.ret() // return for false branch endPos := a.b.len() + + for _, v := range a.assigments { + v.Write() + } + for i := len(a.assigments) - 1; i >= 0; i-- { a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i])) + a.b.write(encode(a.assigments[i].n)) } a.b.patch(a.patchTruePosition, encode(a.rets[1])) a.b.patch(a.patchFalsePosition, encode(a.rets[2])) a.b.patch(a.patchNextPosition, encode(endPos)) - return a.prev.retAssigment(a.startedAt, a.b.len()) + return a.prev //.retAssigment(a.startedAt, a.b.len()) } func (a ConditionalState) Long(value int64) Fsm { diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 1b50ce335a..d575550173 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -27,11 +27,11 @@ type FuncState struct { // References that defined inside function. // Should be cleared before exit. - assigments []uniqueid + assigments []AssigmentState } -func (a FuncState) retAssigment(startedAt uint16, endedAt uint16) Fsm { - a.lastStmtOffset = startedAt +func (a FuncState) retAssigment(as AssigmentState) Fsm { + a.assigments = append(a.assigments, as) /// []uniqueid return a } @@ -89,7 +89,7 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP func (a FuncState) Assigment(name string) Fsm { n := a.params.u.next() - a.assigments = append(a.assigments, n) + //a.assigments = append(a.assigments, n) return assigmentFsmTransition(a, a.params, name, n) } @@ -102,7 +102,7 @@ func (a FuncState) Return() Fsm { // Clean internal assigments. for i := len(a.assigments) - 1; i >= 0; i-- { a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i])) + a.b.write(encode(a.assigments[i].n)) } a.b.ret() @@ -123,7 +123,7 @@ func (a FuncState) Return() Fsm { a.b.write(encode(a.lastStmtOffset)) } - return a.prev.retAssigment(a.startedAt, a.b.len()) + return a.prev //.retAssigment(a.startedAt, a.b.len()) } func (a FuncState) Long(value int64) Fsm { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 332720273e..067d41948d 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -5,11 +5,11 @@ type MainState struct { params retAssig uint16 - assigments []uniqueid + assigments []AssigmentState } -func (a MainState) retAssigment(startedAt uint16, endedAt uint16) Fsm { - a.retAssig = startedAt +func (a MainState) retAssigment(as AssigmentState) Fsm { + a.assigments = append(a.assigments, as) return a } @@ -54,14 +54,20 @@ func NewMain(params params) Fsm { func (a MainState) Assigment(name string) Fsm { n := a.params.u.next() - a.assigments = append(a.assigments, n) + //a.assigments = append(a.assigments, n) + a.r.set(name, n) return assigmentFsmTransition(a, a.params, name, n) } func (a MainState) Return() Fsm { + + for _, v := range a.assigments { + v.Write() + } + for i := len(a.assigments) - 1; i >= 0; i-- { a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i])) + a.b.write(encode(a.assigments[i].n)) } a.b.ret() return a diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index de72180ae6..6f31dcbfad 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -6,9 +6,9 @@ type PropertyState struct { params } -func (a PropertyState) retAssigment(startedAt uint16, endedAt uint16) Fsm { - //panic("implement me") - return a +func (a PropertyState) retAssigment(as AssigmentState) Fsm { + panic("implement me") + //return a } func propertyTransition(prev Fsm, params params, name string) Fsm { diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index bdedaa19c8..52b9e33999 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -16,7 +16,7 @@ type Fsm interface { Bytes(b []byte) Fsm Func(name string, args []string, invokeParam string) Fsm Property(name string) Fsm - retAssigment(startedAt uint16, endedAt uint16) Fsm + retAssigment(state AssigmentState) Fsm } type uniqid struct { From 2f510362fbb492d44ce8615a266a088fcf284909 Mon Sep 17 00:00:00 2001 From: Frozen Date: Wed, 9 Dec 2020 21:04:43 +0300 Subject: [PATCH 19/55] Deferred code. --- pkg/ride/compiler2_test.go | 154 +++++++++++++++++------ pkg/ride/compiler_assigment.go | 116 +++++++++++------ pkg/ride/compiler_call_system.go | 93 ++++++++++---- pkg/ride/compiler_call_user.go | 173 ++++++++++++++++++-------- pkg/ride/compiler_conditional.go | 132 ++++++++++++-------- pkg/ride/compiler_func.go | 205 ++++++++++++++++++------------- pkg/ride/compiler_helpers.go | 85 ++++++++++++- pkg/ride/compiler_main.go | 60 ++++++--- pkg/ride/compiler_property.go | 29 +++-- pkg/ride/compiler_state.go | 84 +++++++------ pkg/ride/opcodes.go | 4 +- 11 files changed, 780 insertions(+), 355 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 6ce8e9cc3a..ca10bb3a2a 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -52,35 +52,36 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - //{`V1: true`, "AQa3b8tH", nil, true}, - //{`V1: false`, `AQfeYll6`, nil, false}, - //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, - //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", env, false}, - //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, - //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, - //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - //{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, - //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - //{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, + {`V1: true`, "AQa3b8tH", env, true}, + {`V1: false`, `AQfeYll6`, nil, false}, + {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + {`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, + {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, + {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, + {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, + {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + {`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, + {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, + //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - // + {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - //{fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, + {fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, @@ -174,8 +175,8 @@ func TestCallExternal(t *testing.T) { require.Equal(t, []byte{ OpReturn, - OpRef, 0, 1, - OpRef, 0, 2, + OpRef, 0, 3, + OpRef, 0, 4, OpExternalCall, 0, 3, 0, 2, OpReturn, }, @@ -199,30 +200,75 @@ func TestIfConditionRightByteCode(t *testing.T) { f, err := compileFunction("", 3, []Node{n}) require.NoError(t, err) + /** require.Equal(t, []byte{ + OpReturn, + OpRef, 0, 1, + OpClearCache, 0, 1, OpReturn, OpRef, 0, 2, - OpJumpIfFalse, 0, 11, 0, 15, 0, 19, + OpJumpIfFalse, 0, 0x12, 0, 0x16, 0, 0x1a, OpRef, 0, 3, OpReturn, OpRef, 0, 4, OpReturn, - - OpCache, 0, 1, - - OpReturn, - OpRef, 0, 1, - OpClearCache, 0, 1, OpReturn, }, f.ByteCode) + /**/ + rs, err := f.Run(nil, 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) { + source := `BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + //f, err := compileFunction("", 3, []Node{n}) + //require.NoError(t, err) + + //require.Equal(t, + // []byte{ + // OpReturn, + // OpRef, 0, 3, + // OpRef, 0, 4, + // OpExternalCall, 0, 3, 0, 2, + // OpReturn, + // + // OpRef, 0, 5, + // OpExternalCall, 0, 0x8c, 0, 1, + // OpReturn, + // + // //OpRef, 0, 3, + // //OpReturn, + // //OpRef, 0, 4, + // //OpReturn, + // //OpReturn, + // }, + // script.ByteCode) + + rs, err := script.Run(nil, nil) + require.NoError(t, err) + //rs, err := f.Run(nil, nil) + require.NoError(t, err) + require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, false, rs.Result()) +} + //func a() = 1; a() == 1 func TestDoubleCall(t *testing.T) { n := &FunctionDeclarationNode{ @@ -248,20 +294,22 @@ func TestDoubleCall(t *testing.T) { f, err := compileFunction("", 3, []Node{n}) require.NoError(t, err) + /** require.Equal(t, []byte{ OpReturn, OpRef, 0, 1, + OpRef, 0, 2, + OpExternalCall, 0, 3, 0, 2, OpReturn, - OpCall, 0, 1, OpRef, 0, 3, - OpExternalCall, 0, 3, 0, 2, OpReturn, }, f.ByteCode) + /**/ - require.EqualValues(t, 5, f.EntryPoints[""]) + require.EqualValues(t, 1, f.EntryPoints[""]) rs, err := f.Run(nil, nil) require.NoError(t, err) @@ -298,9 +346,9 @@ func TestClearInternalVariables(t *testing.T) { require.Equal(t, []byte{ OpReturn, - OpRef, 0, 1, + OpRef, 0, 2, OpClearCache, 0, 2, - OpClearCache, 0, 1, + OpClearCache, 0, 4, OpReturn, OpReturn, @@ -330,13 +378,12 @@ func TestCallWithConstArg(t *testing.T) { bt := []byte{ OpReturn, - OpRef, 0, 1, // Function execution code. One line: reference to `v` argument. + OpSetArg, 0, 3, 0, 2, // Function execution code. One line: reference to `v` argument. + OpRef, 0, 1, OpReturn, // call function - OpSetArg, 0, 3, 0, 1, - OpCall, 0, 1, - + OpRef, 0, 2, OpReturn, } @@ -767,8 +814,17 @@ func Test777(t *testing.T) { assert.Equal(t, true, r.Result()) } +/* +func abc() = 5 +func cba() = 10 +if abc() == cba() then { + true +} else { + false +} +*/ func Test888(t *testing.T) { - source := `BAoBAAAAAWYAAAAACQAAAgAAAAECAAAAATEKAQAAAAJmMgAAAAIAAAAFb3duZXIAAAAGaGVpZ2h0BQAAAAZoZWlnaHQJAAAAAAAAAgkBAAAAAmYyAAAAAgkBAAAAAWYAAAAABQAAAAZoZWlnaHQAAAAAAAAAAAFFcqW2` + source := `BAoBAAAAA2FiYwAAAAAAAAAAAAAAAAUKAQAAAANjYmEAAAAAAAAAAAAAAAAKAwkAAAAAAAACCQEAAAADYWJjAAAAAAkBAAAAA2NiYQAAAAAGB0hjUOM=` state := &MockSmartState{ NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { @@ -812,8 +868,26 @@ func Test888(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - _, err = script.Run(env, nil) - require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"") + /** + 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, err := script.Run(env, nil) + require.Equal(t, rs.Result(), false) + //require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"") } /* diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 280364a9fb..8ba05ecc31 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -1,5 +1,7 @@ package ride +import "fmt" + // Assigment: let x = 5 type AssigmentState struct { params @@ -7,17 +9,17 @@ type AssigmentState struct { name string //startedAt uint16 //ret uint16 - constant rideType + //constant rideType // ref id n uniqueid // Clean internal assigments. - assigments []uniqueid + deferred []Deferred + d Deferreds } -func (a AssigmentState) retAssigment(state AssigmentState) Fsm { - //a.ret = pos - panic("assig in assig") +func (a AssigmentState) retAssigment(state Fsm) Fsm { + a.deferred = append(a.deferred, state.(Deferred)) return a } @@ -30,12 +32,12 @@ func (a AssigmentState) Func(name string, args []string, invoke string) Fsm { } func (a AssigmentState) Bytes(b []byte) Fsm { - a.constant = rideBytes(b) + a.deferred = append(a.deferred, a.constant(rideBytes(b))) return a } func (a AssigmentState) Condition() Fsm { - return conditionalTransition(a, a.params) + return conditionalTransition(a, a.params, a.d) } func (a AssigmentState) TrueBranch() Fsm { @@ -47,26 +49,27 @@ func (a AssigmentState) FalseBranch() Fsm { } func (a AssigmentState) String(s string) Fsm { - a.constant = rideString(s) + a.deferred = append(a.deferred, a.constant(rideString(s))) return a } func (a AssigmentState) Boolean(v bool) Fsm { - a.constant = rideBoolean(v) + a.deferred = append(a.deferred, a.constant(rideBoolean(v))) return a } -func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid) Fsm { - return newAssigmentFsm(prev, params, name, n) +func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid, d Deferreds) Fsm { + params.r.set(name, n) + return newAssigmentFsm(prev, params, name, n, d) } -func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid) Fsm { +func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid, d Deferreds) Fsm { return AssigmentState{ prev: prev, params: p, name: name, - //startedAt: p.b.len(), - n: n, + n: n, + d: d, } } @@ -76,8 +79,7 @@ func (a AssigmentState) Assigment(name string) Fsm { params.r = newReferences(params.r) // TODO clear var in var n := a.params.u.next() - a.assigments = append(a.assigments, n) - return assigmentFsmTransition(a, params, name, params.u.next()) + return assigmentFsmTransition(a, params, name, n, a.d) } func (a AssigmentState) Return() Fsm { @@ -94,38 +96,74 @@ func (a AssigmentState) Return() Fsm { // a.b.write(encode(a.n)) // a.b.ret() //} - //a.r.set(a.name, a.n) - //return a.prev.retAssigment(a.startedAt, a.params.b.len()) - return a.prev.retAssigment(a) -} - -func (a AssigmentState) Write() { - //for i := len(a.assigments) - 1; i >= 0; i-- { - // a.b.writeByte(OpClearCache) - // a.b.write(encode(a.assigments[i])) - //} - // constant - if a.constant != nil { - a.c.set(a.n, a.constant, nil, 0, true, a.name) - } else { - a.c.set(a.n, nil, nil, a.b.len(), false, a.name) - a.b.writeByte(OpCache) - a.b.write(encode(a.n)) - a.b.ret() - } a.r.set(a.name, a.n) - return //a.prev.retAssigment(a.startedAt, a.params.b.len()) + a.d.Add(a, a.n, fmt.Sprintf("ref %s", a.name)) + //return a.prev.retAssigment(a.startedAt, a.params.b.len()) + return a.prev //.retAssigment(a) } func (a AssigmentState) Long(value int64) Fsm { - a.constant = rideInt(value) + a.deferred = append(a.deferred, a.constant(rideInt(value))) return a } func (a AssigmentState) Call(name string, argc uint16) Fsm { - return callTransition(a, a.params, name, argc) + return callTransition(a, a.params, name, argc, a.d) } func (a AssigmentState) Reference(name string) Fsm { - return reference(a, a.params, name) + a.deferred = append(a.deferred, reference(a, a.params, name)) + return a +} + +func (a AssigmentState) Write(_ params) { + // constant + //if a.constant != nil { + // a.c.set(a.n, a.constant, nil, 0, true, a.name) + //} else { + //a.c.set(a.n, nil, nil, a.b.len(), false, a.name) + // a.b.writeByte(OpCache) + // a.b.write(encode(a.n)) + // a.b.ret() + //} + //a.r.set(a.name, a.n) + + //for _, v := range a.deferred { + // v.(Clean).Clean() + //} + // + //a.b.ret() + // + //for _, v := range reverse(a.deferred) { + // v.(Write).Write() + //} + + d := a.deferred + + if len(d) == 0 { + panic("writeDeferred len == 0") + } + d2 := reverse(d) + + d2[0].Write(a.params) + + for _, v := range d2 { + v.Clean() + } + + a.b.ret() + for _, v := range d2[1:] { + v.Write(a.params) + } + + //writeDeferred(a.params, a.deferred) + + return //a.prev.retAssigment(a.startedAt, a.params.b.len()) +} + +func (a AssigmentState) Clean() { + //for i := len(a.assigments) - 1; i >= 0; i-- { + a.b.writeByte(OpClearCache) + a.b.write(encode(a.n)) + //} } diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index ab1495948a..e73250147e 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -13,12 +13,14 @@ type CallSystemState struct { // Position where we started write code for current state. startedAt uint16 //retAssig uint16 + deferred []Deferred + deferreds Deferreds + ns []uniqueid } -func (a CallSystemState) retAssigment(_ AssigmentState) Fsm { - //a.retAssig = pos - panic("CallSystemState retAssigment") - //return a +func (a CallSystemState) retAssigment(state Fsm) Fsm { + a.deferred = append(a.deferred, state.(Deferred)) + return a } func (a CallSystemState) Property(name string) Fsm { @@ -30,11 +32,12 @@ func (a CallSystemState) Func(name string, args []string, invoke string) Fsm { } func (a CallSystemState) Bytes(b []byte) Fsm { - return constant(a, a.params, rideBytes(b)) + //return constant(a, a.params, rideBytes(b)) + panic("c") } func (a CallSystemState) Condition() Fsm { - return conditionalTransition(a, a.params) + return conditionalTransition(a, a.params, a.deferreds) } func (a CallSystemState) TrueBranch() Fsm { @@ -45,28 +48,37 @@ func (a CallSystemState) FalseBranch() Fsm { panic("Illegal call `FalseBranch` on CallFsm") } -func (a CallSystemState) String(s string) Fsm { - return str(a, a.params, s) +func (a CallSystemState) String(value string) Fsm { + a.deferred = append(a.deferred, a.constant(rideString(value))) + return a } func (a CallSystemState) Boolean(v bool) Fsm { - return boolean(a, a.params, v) + //return boolean(a, a.params, v) + panic("c") } -func callTransition(prev Fsm, params params, name string, argc uint16) Fsm { +func callTransition(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { if _, ok := params.r.get(name); ok { - return newCallUserFsm(prev, params, name, argc) + return newCallUserFsm(prev, params, name, argc, d) } - return newCallSystemFsm(prev, params, name, argc) + return newCallSystemFsm(prev, params, name, argc, d) } -func newCallSystemFsm(prev Fsm, params params, name string, argc uint16) Fsm { +func newCallSystemFsm(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { + var ns []uniqueid + for i := uint16(0); i < argc; i++ { + ns = append(ns, params.u.next()) + } + return &CallSystemState{ prev: prev, params: params, name: name, argc: argc, startedAt: params.b.len(), + deferreds: d, + ns: ns, } } @@ -76,23 +88,62 @@ func (a CallSystemState) Assigment(name string) Fsm { } func (a CallSystemState) Long(value int64) Fsm { - a.b.push(a.constant(rideInt(value))) + a.deferred = append(a.deferred, a.constant(rideInt(value))) return a } func (a CallSystemState) Return() Fsm { - n, ok := a.f(a.name) - if !ok { - panic(fmt.Sprintf("system function named `%s` not found", a.name)) + + if len(a.ns) != len(a.deferred) { + panic(fmt.Sprintf("ns %d != a.deferred %d", a.argc, len(a.deferred))) } - a.b.externalCall(n, a.argc) - return a.prev + + for i, b := range a.deferred { + if _, ok := isConstant(b); ok { + // skip right now + } else { + a.deferreds.Add(b, a.ns[i], fmt.Sprintf("sys %s param #%d", a.name, i)) + //a.c.set(ns[i], nil, nil, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i)) + //b.Write(a.params) + //a.b.ret() + } + } + + return a.prev.retAssigment(a) } func (a CallSystemState) Call(name string, argc uint16) Fsm { - return callTransition(a, a.params, name, argc) + return callTransition(a, a.params, name, argc, a.deferreds) } func (a CallSystemState) Reference(name string) Fsm { - return reference(a, a.params, name) + a.deferred = append(a.deferred, reference(a, a.params, name)) + return a +} + +func (a CallSystemState) Clean() { + +} + +func (a CallSystemState) Write(_ params) { + if int(a.argc) != len(a.deferred) { + panic(fmt.Sprintf("argc %d != a.deferred %d", a.argc, len(a.deferred))) + } + + for i := range a.ns { + if n, ok := isConstant(a.deferred[i]); ok { + a.b.writeByte(OpRef) + a.b.write(encode(n)) + } else { + n := a.ns[i] + a.b.writeByte(OpRef) + a.b.write(encode(n)) + } + } + + n, ok := a.f(a.name) + if !ok { + panic(fmt.Sprintf("system function named `%s` not found", a.name)) + } + a.b.externalCall(n, a.argc) } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index c940ad66dc..03b63177d0 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -9,27 +9,27 @@ type CallUserState struct { name string argc uint16 // positions of arguments - argn []uniqueid - ret func(s CallUserState, at uint16, to uint16) + //argn []uniqueid + //ret func(s CallUserState, at uint16, to uint16) startedAt uint16 + + deferred []Deferred + deferreds Deferreds } -func (a CallUserState) retAssigment(state AssigmentState) Fsm { - panic("CallUserState retAssigment") - //if a.ret != nil { - // a.ret(a, startedAt, endedAt) - //} - //a.ret = nil - //return a +func (a CallUserState) retAssigment(state Fsm) Fsm { + a.deferred = append(a.deferred, state.(Deferred)) + return a } -func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm { +func newCallUserFsm(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { return &CallUserState{ prev: prev, params: params, name: name, argc: argc, startedAt: params.b.len(), + deferreds: d, } } @@ -42,12 +42,12 @@ func (a CallUserState) Func(name string, args []string, invoke string) Fsm { } func (a CallUserState) Bytes(b []byte) Fsm { - a.argn = append(a.argn, putConstant(a.params, rideBytes(b))) + a.deferred = append(a.deferred, a.constant(rideBytes(b))) return a } func (a CallUserState) Condition() Fsm { - return conditionalTransition(a, a.params) + return conditionalTransition(a, a.params, a.deferreds) } func (a CallUserState) TrueBranch() Fsm { @@ -59,12 +59,12 @@ func (a CallUserState) FalseBranch() Fsm { } func (a CallUserState) String(s string) Fsm { - a.argn = append(a.argn, putConstant(a.params, rideString(s))) + a.deferred = append(a.deferred, a.constant(rideString(s))) return a } func (a CallUserState) Boolean(v bool) Fsm { - a.argn = append(a.argn, putConstant(a.params, rideBoolean(v))) + a.deferred = append(a.deferred, a.constant(rideBoolean(v))) return a } @@ -74,55 +74,130 @@ func (a CallUserState) Assigment(name string) Fsm { } func (a CallUserState) Long(value int64) Fsm { - a.argn = append(a.argn, putConstant(a.params, rideInt(value))) + a.deferred = append(a.deferred, a.constant(rideInt(value))) return a } func (a CallUserState) Return() Fsm { - // check user functions - n, ok := a.r.get(a.name) - if !ok { - panic(fmt.Sprintf("user function `%s` not found", a.name)) - } - for i, pos := range a.argn { - a.b.writeByte(OpSetArg) - funcParamID, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i)) + /* + // check user functions + n, ok := a.r.get(a.name) if !ok { - panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) + panic(fmt.Sprintf("user function `%s` not found", a.name)) + } + for i, pos := range a.argn { + a.b.writeByte(OpSetArg) + funcParamID, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i)) + if !ok { + panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) + } + a.b.write(encode(pos)) + a.b.write(encode(funcParamID)) } - a.b.write(encode(pos)) - a.b.write(encode(funcParamID)) - } - point, ok := a.params.c.get(n) - if !ok { - panic(fmt.Sprintf("no point %d found in cell", n)) - } + _, ok = a.params.c.get(n) + if !ok { + panic(fmt.Sprintf("no point %d found in cell", n)) + } - a.b.call(point.position, a.argc) - return a.prev //.retAssigment(a.startedAt, a.b.len()) + //a.b.call(point.position, a.argc) + a.b.writeByte(OpRef) + a.b.write(encode(n)) + */ + return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len()) } func (a CallUserState) Call(name string, argc uint16) Fsm { - n := a.u.next() - a.c.set(n, nil, nil, 0, false, fmt.Sprintf("function as paramentr: %s$%d", name, n)) - a.argn = append(a.argn, n) - if a.ret != nil { - panic("already assigned") - } - a.ret = func(state CallUserState, startedAt uint16, endedAt uint16) { - a.b.writeByte(OpCache) - a.b.write(encode(n)) - a.b.writeByte(OpPop) - } - return callTransition(a, a.params, name, argc) + //n := a.u.next() + //a.c.set(n, nil, nil, 0, false, fmt.Sprintf("function as paramentr: %s$%d", name, n)) + //a.argn = append(a.argn, n) + //if a.ret != nil { + // panic("already assigned") + //} + //a.ret = func(state CallUserState, startedAt uint16, endedAt uint16) { + // a.b.writeByte(OpCache) + // a.b.write(encode(n)) + // a.b.writeByte(OpPop) + //} + return callTransition(a, a.params, name, argc, a.deferreds) } func (a CallUserState) Reference(name string) Fsm { - rs, ok := a.r.get(name) + a.deferred = append(a.deferred, reference(a, a.params, name)) + //rs, ok := a.r.get(name) + //if !ok { + // panic("CallUserState Reference " + name + " not found") + //} + //a.argn = append(a.argn, rs) + return a +} + +func (a CallUserState) Clean() { + +} + +func (a CallUserState) Write(_ params) { + // check user functions + fn, ok := a.r.get(a.name) if !ok { - panic("CallUserState Reference " + name + " not found") + panic(fmt.Sprintf("user function `%s` not found", a.name)) } - a.argn = append(a.argn, rs) - return a + + if int(a.argc) != len(a.deferred) { + panic(fmt.Sprintf("argc %d != a.deferred %d", a.argc, len(a.deferred))) + } + + var ns []uniqueid + for i := uint16(0); i < a.argc; i++ { + if n, ok := isConstant(a.deferred[i]); ok { + a.b.writeByte(OpSetArg) + a.b.write(encode(n)) + a.b.write(encode(fn + 1 + i)) + ns = append(ns, n) + } else { + n := a.u.next() + a.b.writeByte(OpSetArg) + a.b.write(encode(n)) + a.b.write(encode(fn + 1 + i)) + ns = append(ns, n) + } + } + + a.b.writeByte(OpRef) + a.b.write(encode(fn)) + a.b.ret() + + if len(ns) != len(a.deferred) { + panic(fmt.Sprintf("ns %d != a.deferred %d", a.argc, len(a.deferred))) + } + + for i, b := range a.deferred { + if _, ok := isConstant(b); ok { + // skip right now + } else { + a.c.set(ns[i], nil, nil, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i)) + b.Write(a.params) + a.b.ret() + } + } + + /* + for i := 0; i < a.argc; i++ { + a.b.writeByte(OpSetArg) + funcParamID, ok := a.r.get(a.name) // fmt.Sprintf("%s$%d", a.name, i)) + if !ok { + panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) + } + a.b.write(encode(pos)) + a.b.write(encode(funcParamID + 1 + uniqueid(i))) + } + */ + + //_, ok = a.params.c.get(n) + //if !ok { + // panic(fmt.Sprintf("no point %d found in cell", n)) + //} + + //a.b.call(point.position, a.argc) + } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 3a029beb90..ed777f79c6 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -30,18 +30,18 @@ type ConditionalState struct { rets []uint16 // Clean assigments after exit. - assigments []AssigmentState - //assigmentIndex int + deferred []Deferred + deferreds Deferreds + + condN uniqueid } -func (a ConditionalState) retAssigment(v AssigmentState) Fsm { - //panic("ConditionalState retAssigment") - //return a - a.assigments = append(a.assigments, v) +func (a ConditionalState) retAssigment(v Fsm) Fsm { + a.deferred = append(a.deferred, v.(Deferred)) return a } -func (a ConditionalState) Property(name string) Fsm { +func (a ConditionalState) Property(string) Fsm { panic("ConditionalState Property") } @@ -50,35 +50,31 @@ func (a ConditionalState) Func(name string, args []string, invoke string) Fsm { } func (a ConditionalState) Bytes(b []byte) Fsm { - a.rets = append(a.rets, a.params.b.len()) - return constant(a, a.params, rideBytes(b)) + //a.rets = append(a.rets, a.params.b.len()) + //return constant(a, a.params, rideBytes(b)) + panic("") } -func conditionalTransition(prev Fsm, params params) Fsm { +func conditionalTransition(prev Fsm, params params, deferreds Deferreds) Fsm { return ConditionalState{ prev: prev, params: params, startedAt: params.b.len(), - //assigments: make([][]AssigmentState, 3), - //assigmentIndex: 0, + //deferred: make([[]Deferred, 3), + deferreds: deferreds, } } func (a ConditionalState) Condition() Fsm { a.rets = append(a.rets, a.params.b.len()) - return conditionalTransition(a, a.params) + return conditionalTransition(a, a.params, a.deferreds) } func (a ConditionalState) TrueBranch() Fsm { - a.b.jpmIfFalse() - a.patchTruePosition = a.b.writeStub(2) - a.patchFalsePosition = a.b.writeStub(2) - a.patchNextPosition = a.b.writeStub(2) return a } func (a ConditionalState) FalseBranch() Fsm { - a.b.ret() return a } @@ -86,50 +82,88 @@ func (a ConditionalState) Assigment(name string) Fsm { n := a.params.u.next() //a.assigments = append(a.assigments, n) a.r.set(name, n) - return assigmentFsmTransition(a, a.params, name, n) -} - -func (a ConditionalState) Return() Fsm { - a.b.ret() // return for false branch - endPos := a.b.len() - - for _, v := range a.assigments { - v.Write() - } - - for i := len(a.assigments) - 1; i >= 0; i-- { - a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i].n)) - } - - a.b.patch(a.patchTruePosition, encode(a.rets[1])) - a.b.patch(a.patchFalsePosition, encode(a.rets[2])) - a.b.patch(a.patchNextPosition, encode(endPos)) - return a.prev //.retAssigment(a.startedAt, a.b.len()) + return assigmentFsmTransition(a, a.params, name, n, a.deferreds) } func (a ConditionalState) Long(value int64) Fsm { - a.rets = append(a.rets, a.params.b.len()) - return long(a, a.params, value) + a.deferred = append(a.deferred, a.constant(rideInt(value))) + return a } func (a ConditionalState) Call(name string, argc uint16) Fsm { - a.rets = append(a.rets, a.params.b.len()) - // TODO check if we need ret here - return callTransition(a, a.params, name, argc) + //a.rets = append(a.rets, a.params.b.len()) + return callTransition(a, a.params, name, argc, a.deferreds) + //panic("") } func (a ConditionalState) Reference(name string) Fsm { - a.rets = append(a.rets, a.params.b.len()) - return reference(a, a.params, name) + //a.rets = append(a.rets, a.params.b.len()) + //return reference(a, a.params, name) + //panic("") + a.deferred = append(a.deferred, reference(a, a.params, name)) + return a } func (a ConditionalState) Boolean(v bool) Fsm { - a.rets = append(a.rets, a.params.b.len()) - return boolean(a, a.params, v) + a.deferred = append(a.deferred, a.constant(rideBoolean(v))) + return a } func (a ConditionalState) String(s string) Fsm { - a.rets = append(a.rets, a.params.b.len()) - return str(a, a.params, s) + //a.rets = append(a.rets, a.params.b.len()) + //return str(a, a.params, s) + panic("") +} + +func (a ConditionalState) Return() Fsm { + if len(a.deferred) != 3 { + panic("len(a.deferred) != 3") + } + a.condN = a.u.next() + a.deferreds.Add(a.deferred[0], a.condN, "condition cond") + return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len()) +} + +func (a ConditionalState) Write(_ params) { + if len(a.deferred) != 3 { + panic("len(a.deferred) != 3") + } + + //condB := a.deferred[0] + trueB := a.deferred[1] + falsB := a.deferred[2] + + a.b.writeByte(OpRef) + a.b.write(encode(a.condN)) + + a.b.jpmIfFalse() + a.patchTruePosition = a.b.writeStub(2) + //a.b.write(encode(a.b.len())) + a.patchFalsePosition = a.b.writeStub(2) + a.patchNextPosition = a.b.writeStub(2) + + a.b.patch(a.patchTruePosition, encode(a.b.len())) + //writeDeferred(a.params, trueB) + //a.b.ret() + trueB.Write(a.params) + a.b.ret() + + a.b.patch(a.patchFalsePosition, encode(a.b.len())) + falsB.Write(a.params) + a.b.ret() + + //for _, v := range condB[1:] { + // v.Write(a.params) + //} + + a.b.patch(a.patchNextPosition, encode(a.b.len())) + //for _, v := range condB[1:] { + // v.Clean() + //} + a.b.ret() + + //writeDeferred(a.params, a.deferred) +} +func (a ConditionalState) Clean() { + //panic("ConditionalState Clean") } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index d575550173..47160b608d 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -1,37 +1,52 @@ package ride -import ( - "fmt" -) +import "fmt" type arguments []string -func (a arguments) pos(name string) int { - for i := range a { - if a[i] == name { - return i - } - } - return -1 +type Deferreds interface { + Add(Deferred, uniqueid, string) +} + +type dd struct { + deferred Deferred + uniq uniqueid + debug string +} + +type deferreds struct { + name string + d []dd +} + +func (a *deferreds) Add(deferred2 Deferred, n uniqueid, debug string) { + a.d = append(a.d, dd{ + deferred: deferred2, + uniq: n, + debug: debug, + }) +} + +func (a *deferreds) Get() []dd { + return a.d } type FuncState struct { params - prev Fsm - name string - args arguments - globalScope *references - invokeParam string - lastStmtOffset uint16 - startedAt uint16 + prev Fsm + name string + args arguments + n uniqueid + invokeParam string // References that defined inside function. - // Should be cleared before exit. - assigments []AssigmentState + deferred []Deferred + defers *deferreds + //exe Fsm } -func (a FuncState) retAssigment(as AssigmentState) Fsm { - a.assigments = append(a.assigments, as) /// []uniqueid +func (a FuncState) retAssigment(as Fsm) Fsm { + a.deferred = append(a.deferred, as.(Deferred)) return a } @@ -40,9 +55,9 @@ func (a FuncState) Property(name string) Fsm { } func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { - startedAt := params.b.len() // save reference to global scope, where code lower that function will be able to use it. - globalScope := params.r + n := params.u.next() + params.r.set(name, n) // all variable we add only visible to current scope, // avoid corrupting parent state. params.r = newReferences(params.r) @@ -50,111 +65,101 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP // Function call: verifier or not. if invokeParam != "" { args = append([]string{invokeParam}, args...) - // tx - //pos, ok := params.r.get("tx") - //if !ok { - // panic("no `tx` in function call") - //} - //params.b.writeByte(OpExternalCall) - //params.b.write(encode(math.MaxUint16)) - //params.b.write(encode(0)) - //params.b.writeByte(OpReturn) - //params.r.set(invokeParam, pos) - //params.r.set(invokeParam, params.u.next()) } - //assigments := []uniqueid{} for i := range args { e := params.u.next() //assigments = append(assigments, e) params.r.set(args[i], e) // set to global - globalScope.set(fmt.Sprintf("%s$%d", name, i), e) + //globalScope.set(fmt.Sprintf("%s$%d", name, i), e) } //if invokeParam != "" { // assigments = assigments[1:] //} return &FuncState{ - prev: prev, - name: name, - args: args, - params: params, - //offset: params.b.len(), - globalScope: globalScope, + prev: prev, + name: name, + args: args, + params: params, + n: n, invokeParam: invokeParam, - startedAt: startedAt, - //assigments: assigments, + defers: &deferreds{ + name: "func " + name, + }, } } func (a FuncState) Assigment(name string) Fsm { n := a.params.u.next() //a.assigments = append(a.assigments, n) - return assigmentFsmTransition(a, a.params, name, n) + return assigmentFsmTransition(a, a.params, name, n, a.defers) } func (a FuncState) Return() Fsm { - funcID := a.params.u.next() - a.globalScope.set(a.name, funcID) - a.params.c.set(funcID, nil, nil, a.lastStmtOffset, false, a.name) - // TODO clean args - - // Clean internal assigments. - for i := len(a.assigments) - 1; i >= 0; i-- { - a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i].n)) - } - - a.b.ret() + /* + funcID := a.params.u.next() + a.globalScope.set(a.name, funcID) + a.params.c.set(funcID, nil, nil, a.lastStmtOffset, false, a.name) + // TODO clean args + + // Clean internal assigments. + for i := len(a.assigments) - 1; i >= 0; i-- { + a.b.writeByte(OpClearCache) + a.b.write(encode(a.assigments[i].n)) + } - // if function has invoke param, it means no other code will be provided. - if a.invokeParam != "" { - a.b.startPos() - for i := len(a.args) - 1; i >= 0; i-- { - a.b.writeByte(OpCache) - uniq, ok := a.params.r.get(a.args[i]) - if !ok { - panic("function param `" + a.args[i] + "` not found") + a.b.ret() + + // if function has invoke param, it means no other code will be provided. + if a.invokeParam != "" { + a.b.startPos() + for i := len(a.args) - 1; i >= 0; i-- { + a.b.writeByte(OpCache) + uniq, ok := a.params.r.get(a.args[i]) + if !ok { + panic("function param `" + a.args[i] + "` not found") + } + a.b.write(encode(uniq)) + a.b.writeByte(OpPop) } - a.b.write(encode(uniq)) - a.b.writeByte(OpPop) + a.b.writeByte(OpCall) + a.b.write(encode(a.lastStmtOffset)) } - a.b.writeByte(OpCall) - a.b.write(encode(a.lastStmtOffset)) - } - return a.prev //.retAssigment(a.startedAt, a.b.len()) + + */ + return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len()) } func (a FuncState) Long(value int64) Fsm { - a.lastStmtOffset = a.b.len() - a.params.b.push(a.constant(rideInt(value))) + a.deferred = append(a.deferred, a.constant(rideInt(value))) return a } func (a FuncState) Call(name string, argc uint16) Fsm { - a.lastStmtOffset = a.b.len() - return callTransition(a, a.params, name, argc) + return callTransition(a, a.params, name, argc, a.defers) } func (a FuncState) Reference(name string) Fsm { - a.lastStmtOffset = a.b.len() - return reference(a, a.params, name) + a.deferred = append(a.deferred, reference(a, a.params, name)) + return a } -func (a FuncState) Boolean(v bool) Fsm { - a.lastStmtOffset = a.b.len() - return constant(a, a.params, rideBoolean(v)) +func (a FuncState) Boolean(value bool) Fsm { + a.deferred = append(a.deferred, a.constant(rideBoolean(value))) + return a } func (a FuncState) String(s string) Fsm { - a.lastStmtOffset = a.b.len() - return constant(a, a.params, rideString(s)) + //a.lastStmtOffset = a.b.len() + //return constant(a, a.params, rideString(s)) + panic("a") } func (a FuncState) Condition() Fsm { - a.lastStmtOffset = a.b.len() - return conditionalTransition(a, a.params) + //a.lastStmtOffset = a.b.len() + return conditionalTransition(a, a.params, a.defers) } func (a FuncState) TrueBranch() Fsm { @@ -166,10 +171,38 @@ func (a FuncState) FalseBranch() Fsm { } func (a FuncState) Bytes(b []byte) Fsm { - a.lastStmtOffset = a.b.len() - return constant(a, a.params, rideBytes(b)) + //a.lastStmtOffset = a.b.len() + //return constant(a, a.params, rideBytes(b)) + panic("a") } func (a FuncState) Func(name string, args []string, _ string) Fsm { panic("Illegal call `Func` is `FuncState`") } + +func (a FuncState) Clean() { + +} + +func (a FuncState) Write(_ params) { + pos := a.b.len() + a.params.c.set(a.n, nil, nil, pos, false, fmt.Sprintf("function %s", a.name)) + //writeDeferred(a.params, a.deferred) + if len(a.deferred) != 1 { + panic("len(a.deferred) != 1") + } + a.deferred[0].Write(a.params) + + // End of function body. Clear and write assigments. + 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, nil, pos, false, v.debug) + v.deferred.Write(a.params) + } + +} diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index cebb94187e..12ae1bbbd9 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -72,12 +72,12 @@ func (b *builder) call(id uint16, argc uint16) { b.w.Write(encode(id)) } -func (b *builder) startPos() { - b.startAt = uint16(b.w.Len()) -} +//func (b *builder) startPos() { +// b.startAt = uint16(b.w.Len()) +//} func (b *builder) build() (uint16, []byte) { - return b.startAt, b.w.Bytes() + return 1, b.w.Bytes() } func (b *builder) jpmIfFalse() { @@ -205,3 +205,80 @@ func (a *predef) getn(id int) rideFunction { } return a.prev.getn(id) } + +func reverse(f []Deferred) []Deferred { + out := make([]Deferred, 0, len(f)) + for i := len(f) - 1; i >= 0; i-- { + out = append(out, f[i]) + } + return out +} + +type Deferred interface { + Write + Clean +} + +type deferred struct { + write func() + clean func() +} + +func (a deferred) Write(_ params) { + if a.write != nil { + a.write() + } +} + +func (a deferred) Clean() { + if a.clean != nil { + a.clean() + } +} + +type constantDeferred struct { + n uniqueid +} + +func (a constantDeferred) Write(p params) { + p.b.writeByte(OpRef) + p.b.write(encode(a.n)) +} + +func (a constantDeferred) Clean() { +} + +func NewDeferred(writeFunc func(), cleanFunc func()) Deferred { + return deferred{ + write: writeFunc, + clean: cleanFunc, + } +} + +func NewConstantDeferred(n uniqueid) constantDeferred { + return constantDeferred{n: n} +} + +func writeDeferred(params params, d []Deferred) { + panic("writeDeferred 1") + if len(d) != 1 { + panic("writeDeferred len != 1") + } + d2 := reverse(d) + + d2[0].Write(params) + + for _, v := range d2 { + v.Clean() + } + + params.b.ret() + for _, v := range d2[1:] { + v.Write(params) + } +} + +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 067d41948d..1abe7abc15 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -5,11 +5,12 @@ type MainState struct { params retAssig uint16 - assigments []AssigmentState + deferred []Deferred + deferreds *deferreds } -func (a MainState) retAssigment(as AssigmentState) Fsm { - a.assigments = append(a.assigments, as) +func (a MainState) retAssigment(state Fsm) Fsm { + a.deferred = append(a.deferred, state.(Deferred)) return a } @@ -26,8 +27,8 @@ func (a MainState) Bytes(b []byte) Fsm { } func (a MainState) Condition() Fsm { - a.b.startPos() - return conditionalTransition(a, a.params) + //a.b.startPos() + return conditionalTransition(a, a.params, a.deferreds) } func (a MainState) TrueBranch() Fsm { @@ -49,27 +50,39 @@ type BuildExecutable interface { func NewMain(params params) Fsm { return &MainState{ params: params, + deferreds: &deferreds{ + name: "main", + }, } } func (a MainState) Assigment(name string) Fsm { n := a.params.u.next() //a.assigments = append(a.assigments, n) - a.r.set(name, n) - return assigmentFsmTransition(a, a.params, name, n) + //a.r.set(name, n) + return assigmentFsmTransition(a, a.params, name, n, a.deferreds) } func (a MainState) Return() Fsm { - - for _, v := range a.assigments { - v.Write() + reversed := reverse(a.deferred) + for _, v := range reversed[:1] { + v.Write(a.params) } - - for i := len(a.assigments) - 1; i >= 0; i-- { - a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i].n)) + for _, v := range a.deferreds.Get() { + v.deferred.Clean() } a.b.ret() + for _, v := range reversed[1:] { + v.Write(a.params) + a.b.ret() + } + + for _, v := range a.deferreds.Get() { + pos := a.b.len() + a.c.set(v.uniq, nil, nil, pos, false, v.debug) + v.deferred.Write(a.params) + a.b.ret() + } return a } @@ -78,18 +91,17 @@ func (a MainState) Long(int64) Fsm { } func (a MainState) Call(name string, argc uint16) Fsm { - a.b.startPos() - return callTransition(a, a.params, name, argc) + return callTransition(a, a.params, name, argc, a.deferreds) } func (a MainState) Reference(name string) Fsm { - a.b.startPos() - return reference(a, a.params, name) + a.deferred = append(a.deferred, reference(a, a.params, name)) + return a } func (a MainState) Boolean(v bool) Fsm { - a.b.startPos() - return boolean(a, a.params, v) + a.deferred = append(a.deferred, a.constant(rideBoolean(v))) + return a } func (a MainState) BuildExecutable(version int) *Executable { @@ -101,3 +113,11 @@ func (a MainState) BuildExecutable(version int) *Executable { EntryPoints: map[string]uint16{"": startAt}, } } + +func (a MainState) Write(_ params) { + +} + +func (a MainState) Clean() { + +} diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 6f31dcbfad..4fa066707a 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -4,9 +4,11 @@ type PropertyState struct { prev Fsm name string params + deferred []Deferred + deferreds Deferreds } -func (a PropertyState) retAssigment(as AssigmentState) Fsm { +func (a PropertyState) retAssigment(as Fsm) Fsm { panic("implement me") //return a } @@ -24,10 +26,11 @@ func (a PropertyState) Assigment(name string) Fsm { } func (a PropertyState) Return() Fsm { - a.b.writeByte(OpProperty) - index := a.constant(rideString(a.name)) - a.params.b.write(encode(index)) - return a.prev + //a.b.writeByte(OpProperty) + //index := a.constant(rideString(a.name)) + //a.params.b.write(encode(index)) + //return a.prev.retAssigment(a) + panic("aaaaa") } func (a PropertyState) Long(value int64) Fsm { @@ -35,11 +38,12 @@ func (a PropertyState) Long(value int64) Fsm { } func (a PropertyState) Call(name string, argc uint16) Fsm { - return callTransition(a, a.params, name, argc) + return callTransition(a, a.params, name, argc, a.deferreds) } func (a PropertyState) Reference(name string) Fsm { - return reference(a, a.params, name) + a.deferred = append(a.deferred, reference(a, a.params, name)) + return a } func (a PropertyState) Boolean(v bool) Fsm { @@ -63,7 +67,8 @@ func (a PropertyState) FalseBranch() Fsm { } func (a PropertyState) Bytes(b []byte) Fsm { - return bts(a, a.params, b) + a.deferred = append(a.deferred, a.constant(rideBytes(b))) + return a } func (a PropertyState) Func(name string, args []string, invoke string) Fsm { @@ -73,3 +78,11 @@ func (a PropertyState) Func(name string, args []string, invoke string) Fsm { func (a PropertyState) Property(name string) Fsm { return propertyTransition(a, a.params, name) } + +func (a PropertyState) Clean() { + +} + +func (a PropertyState) Write(_ params) { + panic("PropertyState Write") +} diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 52b9e33999..ebf35b43a5 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -16,7 +16,16 @@ type Fsm interface { Bytes(b []byte) Fsm Func(name string, args []string, invokeParam string) Fsm Property(name string) Fsm - retAssigment(state AssigmentState) Fsm + retAssigment(state Fsm) Fsm + Deferred +} + +type Write interface { + Write(params) +} + +type Clean interface { + Clean() } type uniqid struct { @@ -54,48 +63,49 @@ func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) { a.c.set(id, nil, fn, 0, false, name) } -func (a *params) constant(value rideType) uniqueid { +func (a *params) constant(value rideType) constantDeferred { n := a.u.next() a.c.set(n, value, nil, 0, true, fmt.Sprintf("constant %q", value)) - return n -} - -func long(f Fsm, params params, value int64) Fsm { - params.b.push(params.constant(rideInt(value))) - return f -} - -func boolean(f Fsm, params params, value bool) Fsm { - params.b.push(params.constant(rideBoolean(value))) - return f -} - -func bts(f Fsm, params params, value []byte) Fsm { - params.b.push(params.constant(rideBytes(value))) - return f -} - -func str(a Fsm, params params, value string) Fsm { - params.b.push(params.constant(rideString(value))) - return a -} - -func constant(a Fsm, params params, value rideType) Fsm { - params.b.push(params.constant(value)) - return a -} - -func putConstant(params params, rideType rideType) uniqueid { - index := params.constant(rideType) - return index + return NewConstantDeferred(n) } -func reference(f Fsm, params params, name string) Fsm { +//func long(f Fsm, params params, value int64) Fsm { +// params.b.push(params.constant(rideInt(value))) +// return f +//} + +//func boolean(f Fsm, params params, value bool) Deferred { +// return NewDeferred(func() { +// params.b.push(params.constant(rideBoolean(value))) +// }, nil) +// //return f +//} + +//func bts(f Fsm, params params, value []byte) Fsm { +// params.b.push(params.constant(rideBytes(value))) +// return f +//} + +//func str(a Fsm, params params, value string) Deferred { +// return NewDeferred(func() { +// params.b.push(params.constant(rideString(value))) +// }, nil) +//} + +//func constant(a Fsm, params params, value rideType) Fsm { +// params.b.push(params.constant(value)) +// return a +//} + +//func putConstant(params params, rideType rideType) uniqueid { +// index := params.constant(rideType) +// return index +//} + +func reference(f Fsm, params params, name string) Deferred { pos, ok := params.r.get(name) if !ok { panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) } - //params.b - params.b.ref(pos) - return f + return NewConstantDeferred(pos) } diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index 4d611b4374..96b3d0bfc7 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -17,8 +17,8 @@ const ( OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. OpSetArg //11 0xb - FROM (global) -> TO (local): Set value into cell. Two parameters: constant id and cell id. OpCache //12 0xc - Put constant on stack. One parameter: constant ID. - OpRef //14 0xd = ref id - OpClearCache //15 0xe = ref id + OpRef //13 0xd = ref id + OpClearCache //14 0xe = ref id // odd, will be removed. OpGlobal From 9e7f14c04d13c4d47a126f56fe5d7f8a624cf88c Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 10 Dec 2020 16:09:26 +0300 Subject: [PATCH 20/55] Property state. --- pkg/ride/compiler2_test.go | 73 ++++++++++++++++---------------- pkg/ride/compiler_call_system.go | 7 +-- pkg/ride/compiler_property.go | 18 +++++--- 3 files changed, 54 insertions(+), 44 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index ca10bb3a2a..a6e2cdfc7a 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -52,46 +52,47 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - {`V1: true`, "AQa3b8tH", env, true}, - {`V1: false`, `AQfeYll6`, nil, false}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, - {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - {`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, - {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, - {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, - {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, - {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - {`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, - {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, - {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, - {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, - {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - - {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, - {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, - {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - {fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, + //{`V1: true`, "AQa3b8tH", env, true}, + //{`V1: false`, `AQfeYll6`, nil, false}, + //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + //{`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, + //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, + //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, + //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + //{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, + //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + //{`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, + //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + //{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, + //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, + //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, + //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + // + //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, + //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, + //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, + //{fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, - //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, - //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, + //{`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, + {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, //{`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}, + {`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, env, true}, } { src, err := base64.StdEncoding.DecodeString(test.source) require.NoError(t, err, test.comment) diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index e73250147e..364b1a9774 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -31,9 +31,9 @@ func (a CallSystemState) Func(name string, args []string, invoke string) Fsm { return funcTransition(a, a.params, name, args, invoke) } -func (a CallSystemState) Bytes(b []byte) Fsm { - //return constant(a, a.params, rideBytes(b)) - panic("c") +func (a CallSystemState) Bytes(value []byte) Fsm { + a.deferred = append(a.deferred, a.constant(rideBytes(value))) + return a } func (a CallSystemState) Condition() Fsm { @@ -146,4 +146,5 @@ func (a CallSystemState) Write(_ params) { panic(fmt.Sprintf("system function named `%s` not found", a.name)) } a.b.externalCall(n, a.argc) + a.b.ret() } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 4fa066707a..c4cf0a2077 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -29,8 +29,8 @@ func (a PropertyState) Return() Fsm { //a.b.writeByte(OpProperty) //index := a.constant(rideString(a.name)) //a.params.b.write(encode(index)) - //return a.prev.retAssigment(a) - panic("aaaaa") + return a.prev.retAssigment(a) + //panic("aaaaa") } func (a PropertyState) Long(value int64) Fsm { @@ -67,8 +67,9 @@ func (a PropertyState) FalseBranch() Fsm { } func (a PropertyState) Bytes(b []byte) Fsm { - a.deferred = append(a.deferred, a.constant(rideBytes(b))) - return a + panic("PropertyState Bytes") + //a.deferred = append(a.deferred, a.constant(rideBytes(b))) + //return a } func (a PropertyState) Func(name string, args []string, invoke string) Fsm { @@ -84,5 +85,12 @@ func (a PropertyState) Clean() { } func (a PropertyState) Write(_ params) { - panic("PropertyState Write") + a.deferred[0].Write(a.params) + a.b.writeByte(OpProperty) + deferred := a.constant(rideString(a.name)) + if n, ok := isConstant(deferred); ok { + a.params.b.write(encode(n)) + } else { + panic("not constant") + } } From 02967986a9bca15dd6d791f4f3025c08287faae8 Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 10 Dec 2020 17:00:52 +0300 Subject: [PATCH 21/55] Call function. --- pkg/ride/compiler2_test.go | 27 +++++++++++++++++++++++++++ pkg/ride/compiler_func.go | 25 +++++++++++++------------ pkg/ride/compiler_main.go | 9 +++++++++ pkg/ride/compiler_property.go | 1 + 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index a6e2cdfc7a..2a12ab2766 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -1025,3 +1025,30 @@ func TestNoDuplicateCallToState(t *testing.T) { // t.Log(m2) // //} + +/* +{-# 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) { + source := `AAIDAAAAAAAAAAIIAQAAAAAAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAfQAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAAIBQAAAAJ0eAAAAA9zZW5kZXJQdWJsaWNLZXlQ99ml` + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + rs, err := script.Run(nil, []rideType{testTransferObject()}) + require.NoError(t, err) + require.Equal(t, rs.Result(), true) +} diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 47160b608d..e17d20ea31 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -38,11 +38,11 @@ type FuncState struct { args arguments n uniqueid invokeParam string + paramIds []uniqueid // References that defined inside function. deferred []Deferred defers *deferreds - //exe Fsm } func (a FuncState) retAssigment(as Fsm) Fsm { @@ -54,24 +54,22 @@ func (a FuncState) Property(name string) Fsm { panic("FuncState Property") } -func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { - // save reference to global scope, where code lower that function will be able to use it. +func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { // save reference to global scope, where code lower that function will be able to use it. n := params.u.next() params.r.set(name, n) // all variable we add only visible to current scope, - // avoid corrupting parent state. + // avoid corrupting global scope. params.r = newReferences(params.r) // Function call: verifier or not. if invokeParam != "" { args = append([]string{invokeParam}, args...) } + paramIds := make([]uniqueid, 0, len(args)) for i := range args { e := params.u.next() - //assigments = append(assigments, e) + paramIds = append(paramIds, e) params.r.set(args[i], e) - // set to global - //globalScope.set(fmt.Sprintf("%s$%d", name, i), e) } //if invokeParam != "" { // assigments = assigments[1:] @@ -87,15 +85,19 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP defers: &deferreds{ name: "func " + name, }, + paramIds: paramIds, } } func (a FuncState) Assigment(name string) Fsm { n := a.params.u.next() - //a.assigments = append(a.assigments, n) return assigmentFsmTransition(a, a.params, name, n, a.defers) } +func (a FuncState) ParamIds() []uniqueid { + return a.paramIds +} + func (a FuncState) Return() Fsm { /* funcID := a.params.u.next() @@ -151,10 +153,9 @@ func (a FuncState) Boolean(value bool) Fsm { return a } -func (a FuncState) String(s string) Fsm { - //a.lastStmtOffset = a.b.len() - //return constant(a, a.params, rideString(s)) - panic("a") +func (a FuncState) String(value string) Fsm { + a.deferred = append(a.deferred, a.constant(rideString(value))) + return a } func (a FuncState) Condition() Fsm { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 1abe7abc15..3e930d3dba 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -65,6 +65,15 @@ func (a MainState) Assigment(name string) Fsm { func (a MainState) Return() Fsm { reversed := reverse(a.deferred) + + if f, ok := reversed[0].(FuncState); ok { + for i := len(f.ParamIds()) - 1; i >= 0; i-- { + a.b.writeByte(OpCache) + a.b.write(encode(f.ParamIds()[i])) + a.b.writeByte(OpPop) + } + } + for _, v := range reversed[:1] { v.Write(a.params) } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index c4cf0a2077..e5ede567a2 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -90,6 +90,7 @@ func (a PropertyState) Write(_ params) { deferred := a.constant(rideString(a.name)) if n, ok := isConstant(deferred); ok { a.params.b.write(encode(n)) + a.b.ret() } else { panic("not constant") } From 9c0d640cbc4325d69d3700172651f07c9d69ef9b Mon Sep 17 00:00:00 2001 From: Frozen Date: Sun, 13 Dec 2020 18:59:16 +0300 Subject: [PATCH 22/55] Property invocation changed. --- pkg/ride/compiler2_test.go | 68 ++++++++++++++++++++++++++++++-- pkg/ride/compiler_call_system.go | 8 ++-- pkg/ride/compiler_conditional.go | 11 +++--- pkg/ride/compiler_func.go | 2 +- pkg/ride/compiler_main.go | 2 +- pkg/ride/compiler_property.go | 47 ++++++++++++++-------- pkg/ride/executable.go | 4 ++ pkg/ride/tree_evaluation.go | 2 +- pkg/ride/vm.go | 15 ++++--- pkg/ride/vm_test.go | 8 ++++ 10 files changed, 129 insertions(+), 38 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 2a12ab2766..0bb6f8a935 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -82,9 +82,9 @@ func Test22(t *testing.T) { //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, //{fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, - //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, - //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, - //{`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, + {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, + {`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, @@ -983,6 +983,7 @@ func TestNoDuplicateCallToState(t *testing.T) { assert.NotNil(t, script) rs, err := script.Run(env, []rideType{env.transaction()}) + require.NoError(t, err) for _, c := range rs.Calls() { t.Log(c) } @@ -1052,3 +1053,64 @@ func TestDappVerifyVm(t *testing.T) { require.NoError(t, err) 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` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + rs, err := script.Run(env, nil) + require.NoError(t, err) + require.Equal(t, rs.Result(), true) +} + +func TestProperty(t *testing.T) { + n := &FunctionDeclarationNode{ + invocationParameter: "tx", + Name: "v", + Body: &PropertyNode{ + Name: "id", + Object: &ReferenceNode{ + "tx", + }, + }, + } + tree := &Tree{ + Verifier: n, + LibVersion: 3, + } + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + rs, err := script.Run(env, []rideType{testExchangeWithProofsToObject()}) + require.NoError(t, err) + require.Equal(t, rs.Result(), true) +} diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 364b1a9774..4bed269bd7 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -24,7 +24,7 @@ func (a CallSystemState) retAssigment(state Fsm) Fsm { } func (a CallSystemState) Property(name string) Fsm { - return propertyTransition(a, a.params, name) + return propertyTransition(a, a.params, name, a.deferreds) } func (a CallSystemState) Func(name string, args []string, invoke string) Fsm { @@ -53,9 +53,9 @@ func (a CallSystemState) String(value string) Fsm { return a } -func (a CallSystemState) Boolean(v bool) Fsm { - //return boolean(a, a.params, v) - panic("c") +func (a CallSystemState) Boolean(value bool) Fsm { + a.deferred = append(a.deferred, a.constant(rideBoolean(value))) + return a } func callTransition(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index ed777f79c6..0635ead7b8 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -104,15 +104,14 @@ func (a ConditionalState) Reference(name string) Fsm { return a } -func (a ConditionalState) Boolean(v bool) Fsm { - a.deferred = append(a.deferred, a.constant(rideBoolean(v))) +func (a ConditionalState) Boolean(value bool) Fsm { + a.deferred = append(a.deferred, a.constant(rideBoolean(value))) return a } -func (a ConditionalState) String(s string) Fsm { - //a.rets = append(a.rets, a.params.b.len()) - //return str(a, a.params, s) - panic("") +func (a ConditionalState) String(value string) Fsm { + a.deferred = append(a.deferred, a.constant(rideString(value))) + return a } func (a ConditionalState) Return() Fsm { diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index e17d20ea31..dc6b224a64 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -51,7 +51,7 @@ func (a FuncState) retAssigment(as Fsm) Fsm { } func (a FuncState) Property(name string) Fsm { - panic("FuncState Property") + return propertyTransition(a, a.params, name, a.defers) } func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { // save reference to global scope, where code lower that function will be able to use it. diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 3e930d3dba..7e8db40a4e 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -15,7 +15,7 @@ func (a MainState) retAssigment(state Fsm) Fsm { } func (a MainState) Property(name string) Fsm { - return propertyTransition(a, a.params, name) + return propertyTransition(a, a.params, name, a.deferreds) } func (a MainState) Func(name string, args []string, invoke string) Fsm { diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index e5ede567a2..3e935b0c15 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -1,23 +1,27 @@ package ride +import "fmt" + type PropertyState struct { prev Fsm name string params deferred []Deferred deferreds Deferreds + n uniqueid } func (a PropertyState) retAssigment(as Fsm) Fsm { - panic("implement me") - //return a + a.deferred = append(a.deferred, as) + return a } -func propertyTransition(prev Fsm, params params, name string) Fsm { +func propertyTransition(prev Fsm, params params, name string, d Deferreds) Fsm { return &PropertyState{ - params: params, - prev: prev, - name: name, + params: params, + prev: prev, + name: name, + deferreds: d, } } @@ -29,6 +33,10 @@ func (a PropertyState) Return() Fsm { //a.b.writeByte(OpProperty) //index := a.constant(rideString(a.name)) //a.params.b.write(encode(index)) + + a.n = a.params.u.next() + a.deferreds.Add(a.deferred[0], a.n, fmt.Sprintf("property `%s`", a.name)) + return a.prev.retAssigment(a) //panic("aaaaa") } @@ -68,8 +76,6 @@ func (a PropertyState) FalseBranch() Fsm { func (a PropertyState) Bytes(b []byte) Fsm { panic("PropertyState Bytes") - //a.deferred = append(a.deferred, a.constant(rideBytes(b))) - //return a } func (a PropertyState) Func(name string, args []string, invoke string) Fsm { @@ -77,7 +83,7 @@ func (a PropertyState) Func(name string, args []string, invoke string) Fsm { } func (a PropertyState) Property(name string) Fsm { - return propertyTransition(a, a.params, name) + return propertyTransition(a, a.params, name, a.deferreds) } func (a PropertyState) Clean() { @@ -85,13 +91,20 @@ func (a PropertyState) Clean() { } func (a PropertyState) Write(_ params) { - a.deferred[0].Write(a.params) + a.b.writeByte(OpRef) + a.b.write(encode(a.n)) + next := a.u.next() + a.c.set(next, rideString(a.name), nil, 0, true, fmt.Sprintf("property %s", a.name)) + a.b.writeByte(OpRef) + a.b.write(encode(next)) a.b.writeByte(OpProperty) - deferred := a.constant(rideString(a.name)) - if n, ok := isConstant(deferred); ok { - a.params.b.write(encode(n)) - a.b.ret() - } else { - panic("not constant") - } + a.b.ret() + + //deferred := a.constant(rideString(a.name)) + //if n, ok := isConstant(deferred); ok { + // a.params.b.write(encode(n)) + // a.b.ret() + //} else { + // panic("not constant") + //} } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 00c0a220d5..94dc0fc0a1 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -30,3 +30,7 @@ func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (Rid return v.run() } + +func (a *Executable) run(environment RideEnvironment, arguments []rideType) (rideType, error) { + return nil, nil +} diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 53ec250adf..a9456ce70e 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -76,7 +76,7 @@ func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, arg //} rs2, err := CallFunction2(txID, env, tree, name, args) if err != nil { - return nil, errors.Wrap(err, "call function by vm") + return rs2, errors.Wrap(err, "call function by vm") } //if !rs1.Eq(rs2) { // zap.S().Errorf("%s, result mismatch", txID) diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index db57396fc2..17c23c507a 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -32,7 +32,7 @@ func (m *vm) run() (RideResult, error) { for m.ip < len(m.code) { if numOperations >= limitOperations { - return nil, errors.New("limit operations exceed") + return ScriptResult{calls: m.calls}, errors.New("limit operations exceed") } numOperations++ @@ -69,14 +69,19 @@ func (m *vm) run() (RideResult, error) { m.ip = posFalse } case OpProperty: - obj, err := m.pop() + + //n := m.uint16() + prop, err := m.pop() if err != nil { - return nil, errors.Wrap(err, "failed to get object") + return nil, err //errors.Wrap(err, "no ref %d", n) } - prop := m.ref[m.uint16()].value p, ok := prop.(rideString) if !ok { - return nil, errors.Errorf("invalid property name type '%s'", prop.instanceOf()) + return nil, errors.Errorf("invalid property type '%T'", prop) + } + obj, err := m.pop() + if err != nil { + return nil, errors.Wrap(err, "failed to get object") } v, err := obj.get(string(p)) if err != nil { diff --git a/pkg/ride/vm_test.go b/pkg/ride/vm_test.go index 486d9c4014..c6d0eb2dac 100644 --- a/pkg/ride/vm_test.go +++ b/pkg/ride/vm_test.go @@ -470,3 +470,11 @@ func testTransferObject() rideObject { } return obj } + +func testExchangeWithProofsToObject() rideObject { + obj, err := exchangeWithProofsToObject('T', byte_helpers.ExchangeWithProofs.Transaction) + if err != nil { + panic(err.Error()) + } + return obj +} From 8f7a32a2c619e5f9066b4e1ba6aa71a4ea353d90 Mon Sep 17 00:00:00 2001 From: Frozen Date: Sun, 13 Dec 2020 21:16:30 +0300 Subject: [PATCH 23/55] Property bytecode checked in tests. --- pkg/ride/compiler.go | 43 ++++----- pkg/ride/compiler2_test.go | 162 +++++++++++++++++++++++----------- pkg/ride/compiler_func.go | 1 + pkg/ride/compiler_property.go | 32 +++---- pkg/ride/compiler_test.go | 2 + pkg/ride/executable.go | 58 +++++++++--- pkg/ride/program.go | 67 +++++++------- pkg/ride/vm.go | 70 +++++---------- 8 files changed, 253 insertions(+), 182 deletions(-) diff --git a/pkg/ride/compiler.go b/pkg/ride/compiler.go index 7654bb75b7..118ffc38b8 100644 --- a/pkg/ride/compiler.go +++ b/pkg/ride/compiler.go @@ -11,27 +11,28 @@ import ( ) func Compile(tree *Tree) (RideScript, error) { - fCheck, err := selectFunctionChecker(tree.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "compile") - } - cCheck, err := selectConstantsChecker(tree.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "compile") - } - c := &compiler{ - constants: newRideConstants(), - checkFunction: fCheck, - checkConstant: cCheck, - values: make([]rideValue, 0), - functions: make([]*localFunction, 0), - declarations: make([]rideDeclaration, 0), - patcher: newPatcher(), - } - if tree.IsDApp() { - return c.compileDAppScript(tree) - } - return c.compileSimpleScript(tree) + panic("Compile") + //fCheck, err := selectFunctionChecker(tree.LibVersion) + //if err != nil { + // return nil, errors.Wrap(err, "compile") + //} + //cCheck, err := selectConstantsChecker(tree.LibVersion) + //if err != nil { + // return nil, errors.Wrap(err, "compile") + //} + //c := &compiler{ + // constants: newRideConstants(), + // checkFunction: fCheck, + // checkConstant: cCheck, + // values: make([]rideValue, 0), + // functions: make([]*localFunction, 0), + // declarations: make([]rideDeclaration, 0), + // patcher: newPatcher(), + //} + //if tree.IsDApp() { + // return c.compileDAppScript(tree) + //} + //return c.compileSimpleScript(tree) } type compiler struct { diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 0bb6f8a935..42a482f359 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -52,36 +52,36 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - //{`V1: true`, "AQa3b8tH", env, true}, - //{`V1: false`, `AQfeYll6`, nil, false}, - //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, - //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - //{`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, - //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, - //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, - //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - //{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, - //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - //{`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, - //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - //{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, - //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, - //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, - //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - // - //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, - //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, - //{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - //{fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, + {`V1: true`, "AQa3b8tH", env, true}, + {`V1: false`, `AQfeYll6`, nil, false}, + {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + {`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, + {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, + {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, + {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, + {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + {`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, + {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, + {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, + {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, + {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + + {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, + {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, + {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, + {fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, {`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, @@ -180,6 +180,7 @@ func TestCallExternal(t *testing.T) { OpRef, 0, 4, OpExternalCall, 0, 3, 0, 2, OpReturn, + OpReturn, }, f.ByteCode) } @@ -351,6 +352,8 @@ func TestClearInternalVariables(t *testing.T) { OpClearCache, 0, 2, OpClearCache, 0, 4, OpReturn, + OpRef, 0, 3, OpReturn, OpReturn, + OpRef, 0, 5, OpReturn, OpReturn, OpReturn, }, @@ -1086,31 +1089,86 @@ func TestMultipleProperty(t *testing.T) { require.Equal(t, rs.Result(), true) } +/** +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +@Verifier(tx) +func verify () = ("" == toBase58String(tx.id)) +*/ + func TestProperty(t *testing.T) { - n := &FunctionDeclarationNode{ - invocationParameter: "tx", - Name: "v", - Body: &PropertyNode{ - Name: "id", - Object: &ReferenceNode{ - "tx", + t.Run("test simple property", func(t *testing.T) { + n := &PropertyNode{ + Name: "id", + Object: &ReferenceNode{Name: "tx"}, + } + tree := &Tree{ + LibVersion: 3, + AppVersion: scriptApplicationVersion, + Verifier: n, + } + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + require.Equal(t, + []byte{ + OpReturn, + OpRef, 255, 255, + OpRef, 0, 2, + OpProperty, + OpReturn, + OpReturn, }, - }, - } - tree := &Tree{ - Verifier: n, - LibVersion: 3, - } + script.ByteCode) + _, err = script.run(env, nil) + require.NoError(t, err) + }) + t.Run("test multiple property", func(t *testing.T) { + n := &PropertyNode{ + Name: "assetPair", + Object: &PropertyNode{ + Name: "sellOrder", + Object: &ReferenceNode{Name: "tx"}, + }} + tree := &Tree{ + LibVersion: 3, + AppVersion: scriptApplicationVersion, + Verifier: n, + } - script, err := CompileVerifier("", tree) - require.NoError(t, err) - assert.NotNil(t, script) + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) - env := &MockRideEnvironment{ - transactionFunc: testExchangeWithProofsToObject, - } + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } - rs, err := script.Run(env, []rideType{testExchangeWithProofsToObject()}) - require.NoError(t, err) - require.Equal(t, rs.Result(), true) + require.Equal(t, + []byte{ + OpReturn, + OpRef, 0, 3, + OpRef, 0, 4, + OpProperty, + OpReturn, + OpReturn, + + OpRef, 255, 255, + OpRef, 0, 5, + OpProperty, + OpReturn, + OpReturn, + }, + script.ByteCode) + _, err = script.run(env, nil) + require.NoError(t, err) + }) } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index dc6b224a64..0c36ba01a6 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -204,6 +204,7 @@ func (a FuncState) Write(_ params) { pos := a.b.len() a.c.set(v.uniq, nil, nil, pos, false, v.debug) v.deferred.Write(a.params) + a.b.ret() } } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 3e935b0c15..3588aaf64f 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -6,13 +6,13 @@ type PropertyState struct { prev Fsm name string params - deferred []Deferred + body Deferred deferreds Deferreds n uniqueid } func (a PropertyState) retAssigment(as Fsm) Fsm { - a.deferred = append(a.deferred, as) + a.body = as return a } @@ -30,15 +30,17 @@ func (a PropertyState) Assigment(name string) Fsm { } func (a PropertyState) Return() Fsm { - //a.b.writeByte(OpProperty) - //index := a.constant(rideString(a.name)) - //a.params.b.write(encode(index)) - + // 2 possible variations: + // 1) tx.id => body is reference + // 2) tx.sellOrder.assetPair => body is another property a.n = a.params.u.next() - a.deferreds.Add(a.deferred[0], a.n, fmt.Sprintf("property `%s`", a.name)) - + if n, ok := isConstant(a.body); ok { // body is reference + a.n = n + } else { // body is another property + a.n = a.u.next() + a.deferreds.Add(a.body, a.n, fmt.Sprintf("property== `%s`", a.name)) + } return a.prev.retAssigment(a) - //panic("aaaaa") } func (a PropertyState) Long(value int64) Fsm { @@ -50,7 +52,7 @@ func (a PropertyState) Call(name string, argc uint16) Fsm { } func (a PropertyState) Reference(name string) Fsm { - a.deferred = append(a.deferred, reference(a, a.params, name)) + a.body = reference(a, a.params, name) return a } @@ -94,17 +96,9 @@ func (a PropertyState) Write(_ params) { a.b.writeByte(OpRef) a.b.write(encode(a.n)) next := a.u.next() - a.c.set(next, rideString(a.name), nil, 0, true, fmt.Sprintf("property %s", a.name)) + a.c.set(next, rideString(a.name), nil, 0, true, fmt.Sprintf("property?? %s", a.name)) a.b.writeByte(OpRef) a.b.write(encode(next)) a.b.writeByte(OpProperty) a.b.ret() - - //deferred := a.constant(rideString(a.name)) - //if n, ok := isConstant(deferred); ok { - // a.params.b.write(encode(n)) - // a.b.ret() - //} else { - // panic("not constant") - //} } diff --git a/pkg/ride/compiler_test.go b/pkg/ride/compiler_test.go index 5bba405490..558a662599 100644 --- a/pkg/ride/compiler_test.go +++ b/pkg/ride/compiler_test.go @@ -13,6 +13,7 @@ func c(values ...rideType) []rideType { return values } +/* func TestSimpleScriptsCompilation(t *testing.T) { for _, test := range []struct { comment string @@ -95,6 +96,7 @@ func TestSimpleScriptsCompilation(t *testing.T) { assert.ElementsMatch(t, test.constants, script.Constants, test.comment) } } +*/ func TestDAppScriptsCompilation(t *testing.T) { for _, test := range []struct { diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 94dc0fc0a1..41705b371d 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -1,5 +1,10 @@ package ride +import ( + "github.com/pkg/errors" + "github.com/wavesplatform/gowaves/pkg/proto" +) + type Executable struct { LibVersion int ByteCode []byte @@ -8,17 +13,56 @@ type Executable struct { } func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (RideResult, error) { - fSelect, err := selectFunctions(a.LibVersion) + vm, err := a.makeVm(environment, arguments) + if err != nil { + return nil, err + } + v, err := vm.run() if err != nil { return nil, err } + switch tv := v.(type) { + case rideBoolean: + return ScriptResult{res: bool(tv), operations: vm.numOperations, calls: vm.calls}, nil + case rideObject: + actions, err := objectToActions(vm.env, tv) + if err != nil { + return nil, errors.Wrap(err, "failed to convert evaluation result") + } + return DAppResult{res: true, actions: actions, msg: "", calls: vm.calls}, nil + case rideList: + actions := make([]proto.ScriptAction, len(tv)) + for i, item := range tv { + a, err := convertToAction(vm.env, item) + if err != nil { + return nil, errors.Wrap(err, "failed to convert evaluation result") + } + actions[i] = a + } + return DAppResult{res: true, actions: actions, calls: vm.calls}, nil + default: + return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) + } +} - provider, err := selectFunctionNameProvider(a.LibVersion) +func (a *Executable) run(environment RideEnvironment, arguments []rideType) (rideType, error) { + vm, err := a.makeVm(environment, arguments) if err != nil { return nil, err } + return vm.run() +} - v := vm{ +func (a *Executable) makeVm(environment RideEnvironment, arguments []rideType) (*vm, error) { + fSelect, err := selectFunctions(a.LibVersion) + if err != nil { + return nil, err + } + provider, err := selectFunctionNameProvider(a.LibVersion) + if err != nil { + return nil, err + } + return &vm{ code: a.ByteCode, ip: int(a.EntryPoints[""]), functions: mergeWithPredefined(fSelect, predefined), @@ -26,11 +70,5 @@ func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (Rid env: environment, ref: a.References, stack: arguments, - } - - return v.run() -} - -func (a *Executable) run(environment RideEnvironment, arguments []rideType) (rideType, error) { - return nil, nil + }, nil } diff --git a/pkg/ride/program.go b/pkg/ride/program.go index 6edb89ef9e..a701d41c45 100644 --- a/pkg/ride/program.go +++ b/pkg/ride/program.go @@ -1,7 +1,5 @@ package ride -import "github.com/pkg/errors" - type callable struct { entryPoint int parameterName string @@ -19,6 +17,7 @@ type SimpleScript struct { Constants []rideType } +/* func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { fs, err := selectFunctions(s.LibVersion) if err != nil { @@ -49,6 +48,7 @@ func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { } return r, nil } +*/ func (s *SimpleScript) code() []byte { return s.Code @@ -62,37 +62,38 @@ type DAppScript struct { } func (s *DAppScript) Run(env RideEnvironment) (RideResult, error) { - if _, ok := s.EntryPoints[""]; !ok { - return nil, errors.Errorf("no verifier") - } - fs, err := selectFunctions(s.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "script execution failed") - } - gcs, err := selectConstants(s.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "script execution failed") - } - np, err := selectFunctionNameProvider(s.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "script execution failed") - } - m := vm{ - env: env, - code: s.Code, - ip: 0, - constants: s.Constants, - functions: fs, - globals: gcs, - stack: make([]rideType, 0, 2), - //calls: make([]frame, 0, 2), - functionName: np, - } - r, err := m.run() - if err != nil { - return nil, errors.Wrap(err, "script execution failed") - } - return r, nil + panic("DAppScript") + //if _, ok := s.EntryPoints[""]; !ok { + // return nil, errors.Errorf("no verifier") + //} + //fs, err := selectFunctions(s.LibVersion) + //if err != nil { + // return nil, errors.Wrap(err, "script execution failed") + //} + //gcs, err := selectConstants(s.LibVersion) + //if err != nil { + // return nil, errors.Wrap(err, "script execution failed") + //} + //np, err := selectFunctionNameProvider(s.LibVersion) + //if err != nil { + // return nil, errors.Wrap(err, "script execution failed") + //} + //m := vm{ + // env: env, + // code: s.Code, + // ip: 0, + // constants: s.Constants, + // functions: fs, + // globals: gcs, + // stack: make([]rideType, 0, 2), + // //calls: make([]frame, 0, 2), + // functionName: np, + //} + //r, err := m.run() + //if err != nil { + // return nil, errors.Wrap(err, "script execution failed") + //} + //return r, nil } func (s *DAppScript) code() []byte { diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 17c23c507a..27a3475bbe 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -3,38 +3,37 @@ package ride import ( "encoding/binary" - //im "github.com/frozen/immutable_map" "github.com/pkg/errors" - "github.com/wavesplatform/gowaves/pkg/proto" ) +const limitOperations = 20000 + type vm struct { - env RideEnvironment - code []byte - ip int - constants []rideType - functions func(int) rideFunction - globals func(int) rideConstructor - stack []rideType - functionName func(int) string - jmps []int - ref map[uint16]point - cache bool - calls []callLog + env RideEnvironment + code []byte + ip int + constants []rideType + functions func(int) rideFunction + globals func(int) rideConstructor + stack []rideType + functionName func(int) string + jmps []int + ref map[uint16]point + cache bool + calls []callLog + numOperations int } -func (m *vm) run() (RideResult, error) { - numOperations := 0 - limitOperations := 20000 +func (m *vm) run() (rideType, error) { //if m.stack != nil { // m.stack = m.stack[0:0] //} for m.ip < len(m.code) { - if numOperations >= limitOperations { - return ScriptResult{calls: m.calls}, errors.New("limit operations exceed") + if m.numOperations >= limitOperations { + return nil, errors.New("limit operations exceed") } - numOperations++ + m.numOperations++ op := m.code[m.ip] m.ip++ @@ -116,12 +115,10 @@ func (m *vm) run() (RideResult, error) { result: res, }) if err != nil { - return nil, errors.Wrapf(err, "iteration %d", numOperations) + return nil, errors.Wrapf(err, "iteration %d", m.numOperations) } if isThrow(res) { - return ScriptResult{ - calls: m.calls, - }, errors.Errorf("terminated execution by throw with message %q on iteration %d", res, numOperations) + return nil, errors.Errorf("terminated execution by throw with message %q on iteration %d", res, m.numOperations) } m.push(res) case OpReturn: @@ -132,28 +129,7 @@ func (m *vm) run() (RideResult, error) { if err != nil { return nil, errors.Wrap(err, "failed to get result value") } - switch tv := v.(type) { - case rideBoolean: - return ScriptResult{res: bool(tv), operations: numOperations, calls: m.calls}, nil - case rideObject: - actions, err := objectToActions(m.env, tv) - if err != nil { - return nil, errors.Wrap(err, "failed to convert evaluation result") - } - return DAppResult{res: true, actions: actions, msg: "", calls: m.calls}, nil - case rideList: - actions := make([]proto.ScriptAction, len(tv)) - for i, item := range tv { - a, err := convertToAction(m.env, item) - if err != nil { - return nil, errors.Wrap(err, "failed to convert evaluation result") - } - actions[i] = a - } - return DAppResult{res: true, actions: actions, calls: m.calls}, nil - default: - return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) - } + return v, nil } return nil, errors.New("no result after script execution") } @@ -208,7 +184,7 @@ func (m *vm) run() (RideResult, error) { } default: - return nil, errors.Errorf("unknown code %#x, at iteration %d", op, numOperations) + return nil, errors.Errorf("unknown code %#x, at iteration %d", op, m.numOperations) } } return nil, errors.New("broken code") From f01939c30c62dfd49ed7e7bf08e0cd5d30c90335 Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 15 Dec 2020 16:54:43 +0300 Subject: [PATCH 24/55] Reversed tree. --- pkg/ride/code_samples.go | 3 +- pkg/ride/compiler2_test.go | 248 ++++++++++++++++++++++++++++--- pkg/ride/compiler_assigment.go | 82 +++------- pkg/ride/compiler_call_system.go | 9 +- pkg/ride/compiler_call_user.go | 29 +--- pkg/ride/compiler_conditional.go | 13 +- pkg/ride/compiler_func.go | 42 +----- pkg/ride/compiler_helpers.go | 80 +++++----- pkg/ride/compiler_main.go | 12 +- pkg/ride/compiler_property.go | 7 +- pkg/ride/compiler_state.go | 4 +- pkg/ride/result.go | 4 +- pkg/ride/reverse_tree.go | 61 ++++++++ pkg/ride/reverse_tree_test.go | 141 ++++++++++++++++++ pkg/ride/reversed_tree.go | 59 ++++++++ pkg/ride/tree_evaluation.go | 20 +-- pkg/ride/vm.go | 2 +- 17 files changed, 594 insertions(+), 222 deletions(-) create mode 100644 pkg/ride/reverse_tree.go create mode 100644 pkg/ride/reverse_tree_test.go create mode 100644 pkg/ride/reversed_tree.go diff --git a/pkg/ride/code_samples.go b/pkg/ride/code_samples.go index 9b37602077..8b680718d9 100644 --- a/pkg/ride/code_samples.go +++ b/pkg/ride/code_samples.go @@ -10,4 +10,5 @@ func getInt(key: String) = { let a = getInt("5") let b = getInt("6") -a == b` +a == b +` diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 42a482f359..02d38373ee 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -180,7 +180,6 @@ func TestCallExternal(t *testing.T) { OpRef, 0, 4, OpExternalCall, 0, 3, 0, 2, OpReturn, - OpReturn, }, f.ByteCode) } @@ -352,8 +351,8 @@ func TestClearInternalVariables(t *testing.T) { OpClearCache, 0, 2, OpClearCache, 0, 4, OpReturn, - OpRef, 0, 3, OpReturn, OpReturn, - OpRef, 0, 5, OpReturn, OpReturn, + OpRef, 0, 3, OpCache, 0, 2, OpReturn, OpReturn, + OpRef, 0, 5, OpCache, 0, 4, OpReturn, OpReturn, OpReturn, }, @@ -385,10 +384,12 @@ func TestCallWithConstArg(t *testing.T) { OpSetArg, 0, 3, 0, 2, // Function execution code. One line: reference to `v` argument. OpRef, 0, 1, OpReturn, + OpReturn, // call function OpRef, 0, 2, OpReturn, + OpReturn, } //require.Equal(t, 1, 1, bt) @@ -552,15 +553,10 @@ func TestCompileDapp(t *testing.T) { } /* - - -base64:AwoBAAAAAWYAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBwAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAWEFAAAAByRtYXRjaDAAAAAAAAAAAAEAAAAAAAAAAAAEAAAAAWEJAQAAAAFmAAAAAQIAAAABYQQAAAABYgkBAAAAAWYAAAABAgAAAAFiBAAAAAFjCQEAAAABZgAAAAECAAAAAWMEAAAAAWQJAQAAAAFmAAAAAQIAAAABZAQAAAABZQkBAAAAAWYAAAABAgAAAAFlAwkAAAAAAAACCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIFAAAAAWEFAAAAAWIFAAAAAWMFAAAAAWQFAAAAAWUAAAAAAAAAAAUJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V5B4xspLY= - - -*/ + */ func Test2121(t *testing.T) { - source := `AwoBAAAAAWYAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBwAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAWEFAAAAByRtYXRjaDAAAAAAAAAAAAEAAAAAAAAAAAAEAAAAAWEJAQAAAAFmAAAAAQIAAAABYQQAAAABYgkBAAAAAWYAAAABAgAAAAFiBAAAAAFjCQEAAAABZgAAAAECAAAAAWMEAAAAAWQJAQAAAAFmAAAAAQIAAAABZAQAAAABZQkBAAAAAWYAAAABAgAAAAFlAwkAAAAAAAACCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIFAAAAAWEFAAAAAWIFAAAAAWMFAAAAAWQFAAAAAWUAAAAAAAAAAAUJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V5B4xspLY=` + source := `BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=` state := &MockSmartState{ NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { return byte_helpers.TransferWithProofs.Transaction, nil @@ -568,6 +564,12 @@ func Test2121(t *testing.T) { RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { return &proto.BinaryDataEntry{}, nil }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + rs, err := strconv.ParseInt(key, 10, 64) + return &proto.IntegerDataEntry{ + Value: rs, + }, err + }, } env := &MockRideEnvironment{ transactionFunc: testTransferObject, @@ -608,7 +610,12 @@ func Test2121(t *testing.T) { assert.NotNil(t, res) r, ok := res.(ScriptResult) assert.True(t, ok) - assert.Equal(t, true, r.Result()) + + for i := range r.calls { + t.Log(r.calls[i]) + } + + assert.Equal(t, false, r.Result()) } /* @@ -815,7 +822,7 @@ func Test777(t *testing.T) { assert.NotNil(t, res) r, ok := res.(ScriptResult) assert.True(t, ok) - assert.Equal(t, true, r.Result()) + assert.Equal(t, false, r.Result()) } /* @@ -1089,15 +1096,6 @@ func TestMultipleProperty(t *testing.T) { require.Equal(t, rs.Result(), true) } -/** -{-# STDLIB_VERSION 3 #-} -{-# SCRIPT_TYPE ACCOUNT #-} -{-# CONTENT_TYPE DAPP #-} - -@Verifier(tx) -func verify () = ("" == toBase58String(tx.id)) -*/ - func TestProperty(t *testing.T) { t.Run("test simple property", func(t *testing.T) { n := &PropertyNode{ @@ -1172,3 +1170,211 @@ func TestProperty(t *testing.T) { require.NoError(t, err) }) } + +/* +{-# STDLIB_VERSION 4 #-} +{-# CONTENT_TYPE EXPRESSION #-} +{-# SCRIPT_TYPE ACCOUNT #-} + +let x = 1 + 1 +x == x +*/ +func TestCacheInMain(t *testing.T) { + source := `BAQAAAABeAkAAGQAAAACAAAAAAAAAAABAAAAAAAAAAABCQAAAAAAAAIFAAAAAXgFAAAAAXgu3TzS` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + require.Equal(t, + []byte{ + OpReturn, + OpRef, 0, 1, + OpRef, 0, 1, + OpExternalCall, 0, 3, 0, 2, + OpClearCache, 0, 1, + OpReturn, + + OpRef, 0, 4, + OpRef, 0, 5, + OpExternalCall, 0, 5, 0, 2, + OpCache, 0, 1, + OpReturn, + OpReturn, + }, + script.ByteCode) + + rs, err := script.Run(env, nil) + require.NoError(t, err) + require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, rs.Result(), true) +} + +/* +{-# STDLIB_VERSION 4 #-} +{-# CONTENT_TYPE EXPRESSION #-} +{-# SCRIPT_TYPE ACCOUNT #-} + +func abc() = { + let x = 1 + 1 + x == x +} +abc() +*/ +func TestCacheInFunc(t *testing.T) { + source := `BAoBAAAAA2FiYwAAAAAEAAAAAXgJAABkAAAAAgAAAAAAAAAAAQAAAAAAAAAAAQkAAAAAAAACBQAAAAF4BQAAAAF4CQEAAAADYWJjAAAAAJz8J24=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + require.Equal(t, + []byte{ + OpReturn, + OpRef, 0, 1, + OpReturn, + OpReturn, + + OpRef, 0, 2, + OpRef, 0, 2, + OpExternalCall, 0, 3, 0, 2, + OpClearCache, 0, 2, + OpReturn, + OpRef, 0, 5, + OpRef, 0, 6, + OpExternalCall, 0, 5, 0, 2, + OpCache, 0, 2, + OpReturn, + + OpReturn, + OpReturn, + }, + script.ByteCode) + + rs, err := script.Run(env, nil) + require.NoError(t, err) + require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, rs.Result(), true) +} + +/* +func getInt(key: String) = { + match getInteger(this, key) { + case x : Int => x + case _ => 0 + } +} +*/ +func TestCacheWithIf(t *testing.T) { + n := &FunctionDeclarationNode{ + Name: "abc", + Arguments: []string{"key"}, + Body: &AssignmentNode{ + Name: "$match0", + Expression: &FunctionCallNode{ + Name: "1050", + Arguments: []Node{ + &ReferenceNode{Name: "this"}, + &ReferenceNode{Name: "key"}, + }, + }, + Block: &ConditionalNode{ + Condition: &FunctionCallNode{ + Name: "1", + Arguments: []Node{ + &ReferenceNode{Name: "$match0"}, + &StringNode{Value: "Int"}, + }, + }, + TrueExpression: &AssignmentNode{ + Name: "a", + Expression: &ReferenceNode{Name: "$match0"}, + Block: &ReferenceNode{Name: "a"}, + }, + FalseExpression: &LongNode{Value: 0}, + }, + }, + } + + tree := &Tree{ + LibVersion: 3, + AppVersion: scriptApplicationVersion, + Verifier: n, + } + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + /* + require.Equal(t, + []byte{ + OpReturn, + OpRef, 0, 11, + OpJumpIfFalse, 0x0, 11, 0x0, 15, 0x0, 19, + OpRef, 0x0, 0x9, 0x1, // true 11 + OpRef, 0x0, 0xa, 0x1, // false 15 + + // next 19 + + OpClearCache, 0, 11, + OpClearCache, 0, 11, + OpReturn, + //OpRef, 0, 5, + //OpProperty, + //OpReturn, + //OpReturn, + }, + script.ByteCode) + */ + + _, err = script.run(env, nil) + require.NoError(t, err) +} + +func TestCacheInFunc1111111(t *testing.T) { + source := `BAkAAAAAAAACCQAAZAAAAAIAAAAAAAAAAAUJAABoAAAAAgAAAAAAAAAABQAAAAAAAAAABQAAAAAAAAAAHnckcUY=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + rs, err := script.Run(env, nil) + require.NoError(t, err) + //require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, rs.Result(), true) +} diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 8ba05ecc31..bcee45faf7 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -14,12 +14,12 @@ type AssigmentState struct { n uniqueid // Clean internal assigments. - deferred []Deferred - d Deferreds + body Deferred + d Deferreds } -func (a AssigmentState) retAssigment(state Fsm) Fsm { - a.deferred = append(a.deferred, state.(Deferred)) +func (a AssigmentState) backward(state Fsm) Fsm { + a.body = state.(Deferred) return a } @@ -32,7 +32,7 @@ func (a AssigmentState) Func(name string, args []string, invoke string) Fsm { } func (a AssigmentState) Bytes(b []byte) Fsm { - a.deferred = append(a.deferred, a.constant(rideBytes(b))) + a.body = a.constant(rideBytes(b)) return a } @@ -49,12 +49,12 @@ func (a AssigmentState) FalseBranch() Fsm { } func (a AssigmentState) String(s string) Fsm { - a.deferred = append(a.deferred, a.constant(rideString(s))) + a.body = a.constant(rideString(s)) return a } func (a AssigmentState) Boolean(v bool) Fsm { - a.deferred = append(a.deferred, a.constant(rideBoolean(v))) + a.body = a.constant(rideBoolean(v)) return a } @@ -83,27 +83,13 @@ func (a AssigmentState) Assigment(name string) Fsm { } func (a AssigmentState) Return() Fsm { - //for i := len(a.assigments) - 1; i >= 0; i-- { - // a.b.writeByte(OpClearCache) - // a.b.write(encode(a.assigments[i])) - //} - //// constant - //if a.constant != nil { - // a.c.set(a.n, a.constant, nil, 0, true, a.name) - //} else { - // a.c.set(a.n, nil, nil, a.startedAt, false, a.name) - // a.b.writeByte(OpCache) - // a.b.write(encode(a.n)) - // a.b.ret() - //} a.r.set(a.name, a.n) a.d.Add(a, a.n, fmt.Sprintf("ref %s", a.name)) - //return a.prev.retAssigment(a.startedAt, a.params.b.len()) - return a.prev //.retAssigment(a) + return a.prev } func (a AssigmentState) Long(value int64) Fsm { - a.deferred = append(a.deferred, a.constant(rideInt(value))) + a.body = a.constant(rideInt(value)) return a } @@ -112,53 +98,19 @@ func (a AssigmentState) Call(name string, argc uint16) Fsm { } func (a AssigmentState) Reference(name string) Fsm { - a.deferred = append(a.deferred, reference(a, a.params, name)) + a.body = reference(a, a.params, name) return a } -func (a AssigmentState) Write(_ params) { - // constant - //if a.constant != nil { - // a.c.set(a.n, a.constant, nil, 0, true, a.name) - //} else { - //a.c.set(a.n, nil, nil, a.b.len(), false, a.name) - // a.b.writeByte(OpCache) - // a.b.write(encode(a.n)) - // a.b.ret() - //} - //a.r.set(a.name, a.n) - - //for _, v := range a.deferred { - // v.(Clean).Clean() - //} - // - //a.b.ret() - // - //for _, v := range reverse(a.deferred) { - // v.(Write).Write() - //} - - d := a.deferred - - if len(d) == 0 { - panic("writeDeferred len == 0") +func (a AssigmentState) Write(_ params, b []byte) { + if a.body == nil { + panic("no body for assigment") } - d2 := reverse(d) - - d2[0].Write(a.params) - - for _, v := range d2 { - v.Clean() - } - + a.body.Write(a.params, nil) + a.b.writeByte(OpCache) + a.b.write(encode(a.n)) a.b.ret() - for _, v := range d2[1:] { - v.Write(a.params) - } - - //writeDeferred(a.params, a.deferred) - - return //a.prev.retAssigment(a.startedAt, a.params.b.len()) + return } func (a AssigmentState) Clean() { diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 4bed269bd7..8a9d69376f 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -18,7 +18,7 @@ type CallSystemState struct { ns []uniqueid } -func (a CallSystemState) retAssigment(state Fsm) Fsm { +func (a CallSystemState) backward(state Fsm) Fsm { a.deferred = append(a.deferred, state.(Deferred)) return a } @@ -109,7 +109,7 @@ func (a CallSystemState) Return() Fsm { } } - return a.prev.retAssigment(a) + return a.prev.backward(a) } func (a CallSystemState) Call(name string, argc uint16) Fsm { @@ -125,7 +125,7 @@ func (a CallSystemState) Clean() { } -func (a CallSystemState) Write(_ params) { +func (a CallSystemState) Write(_ params, b []byte) { if int(a.argc) != len(a.deferred) { panic(fmt.Sprintf("argc %d != a.deferred %d", a.argc, len(a.deferred))) } @@ -146,5 +146,6 @@ func (a CallSystemState) Write(_ params) { panic(fmt.Sprintf("system function named `%s` not found", a.name)) } a.b.externalCall(n, a.argc) - a.b.ret() + //a.b.write(b) + //a.b.ret() } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 03b63177d0..19bd25be46 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -17,7 +17,7 @@ type CallUserState struct { deferreds Deferreds } -func (a CallUserState) retAssigment(state Fsm) Fsm { +func (a CallUserState) backward(state Fsm) Fsm { a.deferred = append(a.deferred, state.(Deferred)) return a } @@ -104,7 +104,7 @@ func (a CallUserState) Return() Fsm { a.b.writeByte(OpRef) a.b.write(encode(n)) */ - return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len()) + return a.prev.backward(a) //.backward(a.startedAt, a.b.len()) } func (a CallUserState) Call(name string, argc uint16) Fsm { @@ -136,7 +136,7 @@ func (a CallUserState) Clean() { } -func (a CallUserState) Write(_ params) { +func (a CallUserState) Write(_ params, b []byte) { // check user functions fn, ok := a.r.get(a.name) if !ok { @@ -165,6 +165,7 @@ func (a CallUserState) Write(_ params) { a.b.writeByte(OpRef) a.b.write(encode(fn)) + a.b.write(b) a.b.ret() if len(ns) != len(a.deferred) { @@ -176,28 +177,8 @@ func (a CallUserState) Write(_ params) { // skip right now } else { a.c.set(ns[i], nil, nil, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i)) - b.Write(a.params) + b.Write(a.params, nil) a.b.ret() } } - - /* - for i := 0; i < a.argc; i++ { - a.b.writeByte(OpSetArg) - funcParamID, ok := a.r.get(a.name) // fmt.Sprintf("%s$%d", a.name, i)) - if !ok { - panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) - } - a.b.write(encode(pos)) - a.b.write(encode(funcParamID + 1 + uniqueid(i))) - } - */ - - //_, ok = a.params.c.get(n) - //if !ok { - // panic(fmt.Sprintf("no point %d found in cell", n)) - //} - - //a.b.call(point.position, a.argc) - } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 0635ead7b8..98845d14ff 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -36,7 +36,7 @@ type ConditionalState struct { condN uniqueid } -func (a ConditionalState) retAssigment(v Fsm) Fsm { +func (a ConditionalState) backward(v Fsm) Fsm { a.deferred = append(a.deferred, v.(Deferred)) return a } @@ -120,10 +120,10 @@ func (a ConditionalState) Return() Fsm { } a.condN = a.u.next() a.deferreds.Add(a.deferred[0], a.condN, "condition cond") - return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len()) + return a.prev.backward(a) //.backward(a.startedAt, a.b.len()) } -func (a ConditionalState) Write(_ params) { +func (a ConditionalState) Write(_ params, b []byte) { if len(a.deferred) != 3 { panic("len(a.deferred) != 3") } @@ -144,11 +144,11 @@ func (a ConditionalState) Write(_ params) { a.b.patch(a.patchTruePosition, encode(a.b.len())) //writeDeferred(a.params, trueB) //a.b.ret() - trueB.Write(a.params) + trueB.Write(a.params, nil) a.b.ret() a.b.patch(a.patchFalsePosition, encode(a.b.len())) - falsB.Write(a.params) + falsB.Write(a.params, nil) a.b.ret() //for _, v := range condB[1:] { @@ -159,7 +159,8 @@ func (a ConditionalState) Write(_ params) { //for _, v := range condB[1:] { // v.Clean() //} - a.b.ret() + //a.b.write(b) + //a.b.ret() //writeDeferred(a.params, a.deferred) } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 0c36ba01a6..9dc3adf2aa 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -45,7 +45,7 @@ type FuncState struct { defers *deferreds } -func (a FuncState) retAssigment(as Fsm) Fsm { +func (a FuncState) backward(as Fsm) Fsm { a.deferred = append(a.deferred, as.(Deferred)) return a } @@ -99,39 +99,7 @@ func (a FuncState) ParamIds() []uniqueid { } func (a FuncState) Return() Fsm { - /* - funcID := a.params.u.next() - a.globalScope.set(a.name, funcID) - a.params.c.set(funcID, nil, nil, a.lastStmtOffset, false, a.name) - // TODO clean args - - // Clean internal assigments. - for i := len(a.assigments) - 1; i >= 0; i-- { - a.b.writeByte(OpClearCache) - a.b.write(encode(a.assigments[i].n)) - } - - a.b.ret() - - // if function has invoke param, it means no other code will be provided. - if a.invokeParam != "" { - a.b.startPos() - for i := len(a.args) - 1; i >= 0; i-- { - a.b.writeByte(OpCache) - uniq, ok := a.params.r.get(a.args[i]) - if !ok { - panic("function param `" + a.args[i] + "` not found") - } - a.b.write(encode(uniq)) - a.b.writeByte(OpPop) - } - a.b.writeByte(OpCall) - a.b.write(encode(a.lastStmtOffset)) - } - - - */ - return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len()) + return a.prev.backward(a) } func (a FuncState) Long(value int64) Fsm { @@ -185,14 +153,14 @@ func (a FuncState) Clean() { } -func (a FuncState) Write(_ params) { +func (a FuncState) Write(_ params, b []byte) { pos := a.b.len() a.params.c.set(a.n, nil, nil, pos, false, fmt.Sprintf("function %s", a.name)) //writeDeferred(a.params, a.deferred) if len(a.deferred) != 1 { panic("len(a.deferred) != 1") } - a.deferred[0].Write(a.params) + a.deferred[0].Write(a.params, nil) // End of function body. Clear and write assigments. for _, v := range a.defers.Get() { @@ -203,7 +171,7 @@ func (a FuncState) Write(_ params) { for _, v := range a.defers.Get() { pos := a.b.len() a.c.set(v.uniq, nil, nil, pos, false, v.debug) - v.deferred.Write(a.params) + v.deferred.Write(a.params, nil) a.b.ret() } diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 12ae1bbbd9..b85190ee7c 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -219,28 +219,28 @@ type Deferred interface { Clean } -type deferred struct { - write func() - clean func() -} - -func (a deferred) Write(_ params) { - if a.write != nil { - a.write() - } -} +//type deferred struct { +// write func() +// clean func() +//} -func (a deferred) Clean() { - if a.clean != nil { - a.clean() - } -} +//func (a deferred) Write(_ params, _ []byte) { +// if a.write != nil { +// a.write() +// } +//} +// +//func (a deferred) Clean() { +// if a.clean != nil { +// a.clean() +// } +//} type constantDeferred struct { n uniqueid } -func (a constantDeferred) Write(p params) { +func (a constantDeferred) Write(p params, _ []byte) { p.b.writeByte(OpRef) p.b.write(encode(a.n)) } @@ -248,35 +248,35 @@ func (a constantDeferred) Write(p params) { func (a constantDeferred) Clean() { } -func NewDeferred(writeFunc func(), cleanFunc func()) Deferred { - return deferred{ - write: writeFunc, - clean: cleanFunc, - } -} +//func NewDeferred(writeFunc func(), cleanFunc func()) Deferred { +// return deferred{ +// write: writeFunc, +// clean: cleanFunc, +// } +//} func NewConstantDeferred(n uniqueid) constantDeferred { return constantDeferred{n: n} } -func writeDeferred(params params, d []Deferred) { - panic("writeDeferred 1") - if len(d) != 1 { - panic("writeDeferred len != 1") - } - d2 := reverse(d) - - d2[0].Write(params) - - for _, v := range d2 { - v.Clean() - } - - params.b.ret() - for _, v := range d2[1:] { - v.Write(params) - } -} +//func writeDeferred(params params, d []Deferred) { +// panic("writeDeferred 1") +// if len(d) != 1 { +// panic("writeDeferred len != 1") +// } +// d2 := reverse(d) +// +// d2[0].Write(params) +// +// for _, v := range d2 { +// v.Clean() +// } +// +// params.b.ret() +// for _, v := range d2[1:] { +// v.Write(params) +// } +//} func isConstant(deferred Deferred) (uniqueid, bool) { v, ok := deferred.(constantDeferred) diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 7e8db40a4e..147c672e61 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -9,7 +9,7 @@ type MainState struct { deferreds *deferreds } -func (a MainState) retAssigment(state Fsm) Fsm { +func (a MainState) backward(state Fsm) Fsm { a.deferred = append(a.deferred, state.(Deferred)) return a } @@ -66,7 +66,7 @@ func (a MainState) Assigment(name string) Fsm { func (a MainState) Return() Fsm { reversed := reverse(a.deferred) - if f, ok := reversed[0].(FuncState); ok { + if f, ok := reversed[0].(FuncState); ok && f.invokeParam != "" { for i := len(f.ParamIds()) - 1; i >= 0; i-- { a.b.writeByte(OpCache) a.b.write(encode(f.ParamIds()[i])) @@ -75,21 +75,21 @@ func (a MainState) Return() Fsm { } for _, v := range reversed[:1] { - v.Write(a.params) + v.Write(a.params, nil) } for _, v := range a.deferreds.Get() { v.deferred.Clean() } a.b.ret() for _, v := range reversed[1:] { - v.Write(a.params) + v.Write(a.params, nil) a.b.ret() } for _, v := range a.deferreds.Get() { pos := a.b.len() a.c.set(v.uniq, nil, nil, pos, false, v.debug) - v.deferred.Write(a.params) + v.deferred.Write(a.params, nil) a.b.ret() } return a @@ -123,7 +123,7 @@ func (a MainState) BuildExecutable(version int) *Executable { } } -func (a MainState) Write(_ params) { +func (a MainState) Write(_ params, _ []byte) { } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index 3588aaf64f..ee9d95c0b5 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -11,7 +11,7 @@ type PropertyState struct { n uniqueid } -func (a PropertyState) retAssigment(as Fsm) Fsm { +func (a PropertyState) backward(as Fsm) Fsm { a.body = as return a } @@ -40,7 +40,7 @@ func (a PropertyState) Return() Fsm { a.n = a.u.next() a.deferreds.Add(a.body, a.n, fmt.Sprintf("property== `%s`", a.name)) } - return a.prev.retAssigment(a) + return a.prev.backward(a) } func (a PropertyState) Long(value int64) Fsm { @@ -92,7 +92,7 @@ func (a PropertyState) Clean() { } -func (a PropertyState) Write(_ params) { +func (a PropertyState) Write(_ params, b []byte) { a.b.writeByte(OpRef) a.b.write(encode(a.n)) next := a.u.next() @@ -100,5 +100,6 @@ func (a PropertyState) Write(_ params) { a.b.writeByte(OpRef) a.b.write(encode(next)) a.b.writeByte(OpProperty) + a.b.write(b) a.b.ret() } diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index ebf35b43a5..894e7ed529 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -16,12 +16,12 @@ type Fsm interface { Bytes(b []byte) Fsm Func(name string, args []string, invokeParam string) Fsm Property(name string) Fsm - retAssigment(state Fsm) Fsm + backward(state Fsm) Fsm Deferred } type Write interface { - Write(params) + Write(params, []byte) } type Clean interface { diff --git a/pkg/ride/result.go b/pkg/ride/result.go index ff4a6d61ad..8547a27d02 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -70,9 +70,9 @@ func (r DAppResult) ScriptActions() proto.ScriptActions { } func (r DAppResult) Eq(other RideResult) bool { - switch other.(type) { + switch v := other.(type) { case DAppResult: - return assert.ObjectsAreEqual(r, other) + return r.res == v.res && assert.ObjectsAreEqual(r.actions, v.actions) default: return false } diff --git a/pkg/ride/reverse_tree.go b/pkg/ride/reverse_tree.go new file mode 100644 index 0000000000..3609f9265c --- /dev/null +++ b/pkg/ride/reverse_tree.go @@ -0,0 +1,61 @@ +package ride + +import "fmt" + +func ReverseTree(n []Node) { + for i := len(n) - 1; i >= 0; i-- { + + } +} + +func reverseTree(n Node, r []*RLet) RNode { + + switch v := n.(type) { + case *FunctionDeclarationNode: + return &RFunc{ + Invocation: v.invocationParameter, + Name: v.Name, + Arguments: v.Arguments, + Body: reverseTree(v.Body, r), + } + case *LongNode: + return &RLong{Value: v.Value} + case *FunctionCallNode: + args := make([]RNode, len(v.Arguments)) + for i := range v.Arguments { + args[i] = reverseTree(v.Arguments[i], nil) + } + return &RCall{Name: v.Name, Arguments: args, Assigments: r} + case *ReferenceNode: + return &RRef{Name: v.Name, Assigments: r} + case *AssignmentNode: + return reverseTree(v.Block, append(r, &RLet{Name: v.Name, Body: reverseTree(v.Expression, r)})) + case *ConditionalNode: + return &RCond{ + Cond: reverseTree(v.Condition, nil), + True: reverseTree(v.TrueExpression, nil), + False: reverseTree(v.FalseExpression, nil), + Assigments: r, + } + case *StringNode: + return &RString{Value: v.Value} + default: + panic(fmt.Sprintf("unknown type %T", n)) + } + +} + +// +//func walkAssigments(n Node, r []*RLet) ([]*RLet, Node) { +// switch v := n.(type) { +// case *AssignmentNode: +// r = append(r, &RLet{ +// Name: v.Name, +// N: 0, +// Body: reverseTree(v.Expression), +// }) +// return walkAssigments(v.Block, r) +// default: +// return r, v +// } +//} diff --git a/pkg/ride/reverse_tree_test.go b/pkg/ride/reverse_tree_test.go new file mode 100644 index 0000000000..9805488109 --- /dev/null +++ b/pkg/ride/reverse_tree_test.go @@ -0,0 +1,141 @@ +package ride + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +/* +func abc(key: String) = { + let x = 1 + let y = 2 + x + y +} +*/ +func TestReverseFunc(t *testing.T) { + n := &FunctionDeclarationNode{ + Name: "abc", + Arguments: []string{"key"}, + Body: &AssignmentNode{ + Name: "x", + Expression: &LongNode{Value: 1}, + Block: &AssignmentNode{ + Name: "y", + Expression: &LongNode{Value: 2}, + Block: &FunctionCallNode{ + Name: "+", + Arguments: []Node{ + &ReferenceNode{Name: "x"}, + &ReferenceNode{Name: "y"}, + }, + }, + }, + }, + } + + rs := reverseTree(n, nil) + + require.Equal(t, &RFunc{ + Invocation: "", + Name: "abc", + Arguments: []string{"key"}, + Body: &RCall{ + Name: "+", + Arguments: []RNode{ + &RRef{Name: "x"}, + &RRef{Name: "y"}, + }, + Assigments: []*RLet{ + {Name: "x", Body: &RLong{Value: 1}}, + {Name: "y", Body: &RLong{Value: 2}}, + }, + }, + }, rs) + +} + +/* +func abc(key: String) = { + match getInteger(this, key) { + case a: Int => + a + case _ => + 0 +} +*/ +func TestReverseFunc2(t *testing.T) { + n := &FunctionDeclarationNode{ + Name: "abc", + Arguments: []string{"key"}, + Body: &AssignmentNode{ + Name: "$match0", + Expression: &FunctionCallNode{ + Name: "1050", + Arguments: []Node{ + &ReferenceNode{Name: "this"}, + &ReferenceNode{Name: "key"}, + }, + }, + Block: &ConditionalNode{ + Condition: &FunctionCallNode{ + Name: "1", + Arguments: []Node{ + &ReferenceNode{Name: "$match0"}, + &StringNode{Value: "Int"}, + }, + }, + TrueExpression: &AssignmentNode{ + Name: "a", + Expression: &ReferenceNode{Name: "$match0"}, + Block: &ReferenceNode{Name: "a"}, + }, + FalseExpression: &LongNode{Value: 0}, + }, + }, + } + + rs := reverseTree(n, nil) + + require.Equal(t, &RFunc{ + Invocation: "", + Name: "abc", + Arguments: []string{"key"}, + Body: &RCond{ + Cond: &RCall{ + Name: "1", + Arguments: []RNode{ + &RRef{Name: "$match0"}, + &RString{Value: "Int"}, + }, + }, + True: &RRef{ + Name: "a", + Assigments: []*RLet{ + { + Name: "a", + Body: &RRef{Name: "$match0"}, + }, + }, + }, + False: &RLong{Value: 0}, + Assigments: []*RLet{ + {Name: "$match0", Body: &RCall{ + Name: "1050", + Arguments: []RNode{ + &RRef{Name: "this"}, + &RRef{Name: "key"}, + }, + }}, + }, + }, + //Assigments: []*RLet{ + // { + // Name: "$match0", + // N: 0, + // Body: nil, + // }, + //}, + }, rs) + +} diff --git a/pkg/ride/reversed_tree.go b/pkg/ride/reversed_tree.go new file mode 100644 index 0000000000..062183db18 --- /dev/null +++ b/pkg/ride/reversed_tree.go @@ -0,0 +1,59 @@ +package ride + +type RNode interface { + RNode() +} + +type RFunc struct { + Invocation string + Name string + Arguments []string + Body RNode +} + +func (a *RFunc) RNode() {} + +type RLet struct { + Name string + //N uniqueid + Body RNode +} + +func (a *RLet) RNode() {} + +type RCond struct { + Cond RNode + True RNode + False RNode + Assigments []*RLet +} + +func (a *RCond) RNode() {} + +type RCall struct { + Name string + Arguments []RNode + Assigments []*RLet + Next RNode +} + +func (a *RCall) RNode() {} + +type RRef struct { + Name string + Assigments []*RLet +} + +func (a *RRef) RNode() {} + +type RLong struct { + Value int64 +} + +func (a *RLong) RNode() {} + +type RString struct { + Value string +} + +func (a *RString) RNode() {} diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index a9456ce70e..fbf2eb8917 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -70,20 +70,20 @@ func CallFunction3(env RideEnvironment, tree *Tree, name string, args proto.Argu } func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - //rs1, err := CallFunction3(env, tree, name, args) - //if err != nil { - // return nil, errors.Wrap(err, "call function by tree") - //} + rs1, err := CallFunction3(env, tree, name, args) + if err != nil { + return nil, errors.Wrap(err, "call function by tree") + } rs2, err := CallFunction2(txID, env, tree, name, args) if err != nil { return rs2, errors.Wrap(err, "call function by vm") } - //if !rs1.Eq(rs2) { - // zap.S().Errorf("%s, result mismatch", txID) - // zap.S().Errorf("tree: %+q", rs1) - // zap.S().Errorf("vm : %+q", rs2) - // return nil, errors.New(txID + ": result mismatch") - //} + if !rs1.Eq(rs2) { + zap.S().Errorf("%s, result mismatch", txID) + zap.S().Errorf("tree: %+q", rs1) + zap.S().Errorf("vm : %+q", rs2) + return nil, errors.New(txID + ": result mismatch") + } return rs2, nil } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 27a3475bbe..0a2a660f09 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -6,7 +6,7 @@ import ( "github.com/pkg/errors" ) -const limitOperations = 20000 +const limitOperations = 50000 type vm struct { env RideEnvironment From 4bdddaac1af7d062769cb1d89ddc7995a191fc9d Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 22 Dec 2020 17:53:41 +0300 Subject: [PATCH 25/55] Fix transitions. --- pkg/ride/code_samples.go | 10 + pkg/ride/compiler2.go | 12 +- pkg/ride/compiler2_test.go | 367 ++++++++++++------------------- pkg/ride/compiler_assigment.go | 37 ++-- pkg/ride/compiler_call_system.go | 7 +- pkg/ride/compiler_call_user.go | 14 +- pkg/ride/compiler_conditional.go | 11 +- pkg/ride/compiler_func.go | 19 +- pkg/ride/compiler_main.go | 5 +- pkg/ride/compiler_state.go | 2 + pkg/ride/compiler_test.go | 161 -------------- pkg/ride/errors.go | 20 ++ pkg/ride/errors_test.go | 14 ++ pkg/ride/executable.go | 6 + pkg/ride/functions_predefined.go | 20 +- pkg/ride/tree_evaluation.go | 2 +- pkg/ride/vm.go | 5 +- 17 files changed, 272 insertions(+), 440 deletions(-) delete mode 100644 pkg/ride/compiler_test.go create mode 100644 pkg/ride/errors.go create mode 100644 pkg/ride/errors_test.go diff --git a/pkg/ride/code_samples.go b/pkg/ride/code_samples.go index 8b680718d9..76f4cfd304 100644 --- a/pkg/ride/code_samples.go +++ b/pkg/ride/code_samples.go @@ -12,3 +12,13 @@ let a = getInt("5") let b = getInt("6") a == b ` + +const finf = ` +func abc() = { + func in() = { + true + } + in() +} +abc() +` diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index f6d13119a9..c4d6d9b4c1 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -85,7 +85,7 @@ func CompileVerifier(txID string, tree *Tree) (*Executable, error) { // return nil, errors.Wrap(err, "invalid declaration") // } //} - return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier)) + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier), tree.IsDApp()) //s.constants[verifier.invocationParameter] = esConstant{c: newTx} //return &treeEvaluator{ // dapp: tree.IsDApp(), @@ -96,7 +96,7 @@ func CompileVerifier(txID string, tree *Tree) (*Executable, error) { } return nil, errors.New("no verifier declaration") } - return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}) + return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, tree.IsDApp()) } type namedArgument struct { @@ -106,7 +106,7 @@ type namedArgument struct { type functionArgumentsCount = int -func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments) (*Executable, functionArgumentsCount, error) { +func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments, isDapp bool) (*Executable, functionArgumentsCount, error) { //s, err := newEvaluationScope(tree.LibVersion, env) //if err != nil { // return nil, errors.Wrap(err, "failed to create scope") @@ -145,7 +145,7 @@ func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments) // //}) //} - rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function)) + rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), isDapp) if err != nil { return rs, 0, err } @@ -193,7 +193,7 @@ func compileVerifier(libVersion int, node Node) (*Executable, error) { } */ -func compileFunction(txID string, libVersion int, nodes []Node) (*Executable, error) { +func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool) (*Executable, error) { fCheck, err := selectFunctionChecker(libVersion) if err != nil { return nil, err @@ -246,5 +246,5 @@ func compileFunction(txID string, libVersion int, nodes []Node) (*Executable, er // Just to write `OpReturn` to bytecode. f = f.Return() - return f.(BuildExecutable).BuildExecutable(libVersion), nil + return f.(BuildExecutable).BuildExecutable(libVersion, isDapp), nil } diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 02d38373ee..c872a7504d 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -52,47 +52,50 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - {`V1: true`, "AQa3b8tH", env, true}, - {`V1: false`, `AQfeYll6`, nil, false}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, - {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - {`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, - {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, - {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, - {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, - {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - {`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, - {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, - {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, - {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, - {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - - {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, - {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true}, - {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, - {fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, - {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, - {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, - {`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, - {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, - //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, + //{`V1: true`, "AQa3b8tH", env, true}, + //{`V1: false`, `AQfeYll6`, nil, false}, + //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + //{`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, + //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, + //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, + //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + //{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, + //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + //{`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, + //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + //{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, + //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, + //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, + //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + //{`let x = {let y = true;y}x`, `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C`, nil, true}, + //{`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}, + //{`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}, + //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, + //{`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, + //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, //{`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}, + //{`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, env, true}, } { src, err := base64.StdEncoding.DecodeString(test.source) require.NoError(t, err, test.comment) @@ -170,7 +173,7 @@ func TestCallExternal(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}) + f, err := compileFunction("", 3, []Node{n}, false) require.NoError(t, err) require.Equal(t, @@ -198,7 +201,7 @@ func TestIfConditionRightByteCode(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}) + f, err := compileFunction("", 3, []Node{n}, false) require.NoError(t, err) /** @@ -292,7 +295,7 @@ func TestDoubleCall(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}) + f, err := compileFunction("", 3, []Node{n}, false) require.NoError(t, err) /** @@ -341,7 +344,7 @@ func TestClearInternalVariables(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}) + f, err := compileFunction("", 3, []Node{n}, false) require.NoError(t, err) require.Equal(t, @@ -376,12 +379,14 @@ func TestCallWithConstArg(t *testing.T) { invocationParameter: "", } - f, err := compileFunction("", 3, []Node{n}) + f, err := compileFunction("", 3, []Node{n}, false) require.NoError(t, err) bt := []byte{ OpReturn, - OpSetArg, 0, 3, 0, 2, // Function execution code. One line: reference to `v` argument. + OpRef, 0, 3, + OpCache, 0, 2, // Function execution code. One line: reference to `v` argument. + OpPop, OpRef, 0, 1, OpReturn, OpReturn, @@ -440,182 +445,6 @@ func TestMultipleCallConstantFuncArgument(t *testing.T) { r, ok := res.(ScriptResult) assert.True(t, ok) assert.Equal(t, true, r.Result()) - - //f, err := compileVerifier(3, n) - //require.NoError(t, err) - - //require.Equal(t, - // []byte{ - // OpUseArg, 0, 1, OpReturn, // arguments section - // OpJump, 0, 0, // Function execution code. One line: reference to `v` argument. - // OpReturn, - // - // OpTrue, OpReturn, // define constant - // - // // call function - // OpSetArg, 0, 1, 0, 9, - // OpCall, 0, 4, - // - // OpReturn, - // }, - // f.ByteCode) - // - //rs, err := f.Run(nil) - //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 TestCompileDapp(t *testing.T) { - source := "AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==" - state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }} - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - checkMessageLengthFunc: func(in1 int) bool { - return true - }, - } - - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - assert.NotNil(t, tree) - - script, err := CompileVerifier("", tree) - require.NoError(t, err) - assert.NotNil(t, script) - - res, err := script.Run(env, nil) - require.NoError(t, err) - assert.NotNil(t, res) - r, ok := res.(ScriptResult) - assert.True(t, ok) - assert.Equal(t, true, r.Result()) -} - -/* - */ - -func Test2121(t *testing.T) { - source := `BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=` - state := &MockSmartState{ - NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }, - RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { - return &proto.BinaryDataEntry{}, nil - }, - RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { - rs, err := strconv.ParseInt(key, 10, 64) - return &proto.IntegerDataEntry{ - Value: rs, - }, err - }, - } - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - checkMessageLengthFunc: func(in1 int) bool { - return true - }, - thisFunc: func() rideType { - addr, err := proto.NewAddressFromString("3MfnF2zbXiM89zxcenPVT9fa4qfVJqeCZzj") - if err != nil { - panic(err) - } - - return rideAddress(addr) - }, - } - - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - assert.NotNil(t, tree) - - t.Log(Decompiler(tree.Verifier)) - - script, err := CompileVerifier("", tree) - require.NoError(t, err) - assert.NotNil(t, script) - - res, err := script.Run(env, nil) - require.NoError(t, err) - assert.NotNil(t, res) - r, ok := res.(ScriptResult) - assert.True(t, ok) - - for i := range r.calls { - t.Log(r.calls[i]) - } - - assert.Equal(t, false, r.Result()) } /* @@ -672,6 +501,11 @@ func TestIfStmt(t *testing.T) { assert.NotNil(t, res) r, ok := res.(ScriptResult) assert.True(t, ok) + + for _, l := range r.calls { + t.Log(l) + } + assert.Equal(t, true, r.Result()) } @@ -947,10 +781,11 @@ func TestNoDuplicateCallToState(t *testing.T) { switch key { case "neutrino_contract": return &proto.StringDataEntry{Value: "3MVHscMp4C3JjeaEiZB6fxeomPZdYEHyamY"}, nil - case "last_confirm_tx": - return &proto.StringDataEntry{Value: "3M9uzVzrAAYEKSHXzKaPhw7iQjwDi9BRJysHZHpbqXJm"}, nil case "control_contract": return &proto.StringDataEntry{Value: "3MQdbE6dK59FHxh5rf4biQdyXhdEf3L1R5W"}, nil + case "last_confirm_tx": + return &proto.StringDataEntry{Value: "3M9uzVzrAAYEKSHXzKaPhw7iQjwDi9BRJysHZHpbqXJm"}, nil + } panic(key) }, @@ -1286,6 +1121,7 @@ func getInt(key: String) = { } */ func TestCacheWithIf(t *testing.T) { + t.Skip() n := &FunctionDeclarationNode{ Name: "abc", Arguments: []string{"key"}, @@ -1328,6 +1164,9 @@ func TestCacheWithIf(t *testing.T) { env := &MockRideEnvironment{ transactionFunc: testExchangeWithProofsToObject, + thisFunc: func() rideType { + return rideAddress{} + }, } /* @@ -1356,8 +1195,69 @@ func TestCacheWithIf(t *testing.T) { require.NoError(t, err) } -func TestCacheInFunc1111111(t *testing.T) { - source := `BAkAAAAAAAACCQAAZAAAAAIAAAAAAAAAAAUJAABoAAAAAgAAAAAAAAAABQAAAAAAAAAABQAAAAAAAAAAHnckcUY=` +/* +{-# STDLIB_VERSION 4 #-} +{-# CONTENT_TYPE EXPRESSION #-} +{-# SCRIPT_TYPE ACCOUNT #-} +func abc(x: String) = true +let y = "7" +abc(y) +*/ +func TestCacheFuncArgs(t *testing.T) { + source := `BAoBAAAAA2FiYwAAAAEAAAABeAYEAAAAAXkCAAAAATcJAQAAAANhYmMAAAABBQAAAAF5eKWK0Q==` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + /* */ + require.Equal(t, + []byte{ + OpReturn, + OpRef, 0, 4, + OpCache, 0, 2, + OpPop, + OpRef, 0, 1, + }, + script.ByteCode[:11]) + /**/ + + rs, err := script.Run(env, nil) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) +} + +/* +@i@func sponsorDeposit(compestart,assetName,compenum) { + let compeNum = toString(compenum); + let compeStart = toString(compestart); + let pmt = extract(i.payment); + let paymentId = pmt.assetId; + let currentKey = toBase58String(i.caller.bytes); + let currentAmount = { + let $match0 = 1050(this,currentKey); + if (instanceOf($match0,"Int")) { + let a = $match0; a + } else { + 0 + }; + } + let newAmount = (currentAmount + pmt.amount); + WriteSet(1100(DataEntry((((compeNum + assetName) + compeStart) + currentKey),newAmount),1100(DataEntry((((compeNum + compeStart) + assetName) + currentKey),compestart),nil))) +} +*/ +func TestLetInLet(t *testing.T) { + source := `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -1373,8 +1273,21 @@ func TestCacheInFunc1111111(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.Run(env, nil) require.NoError(t, err) - //require.Equal(t, 2, len(rs.Calls())) - require.Equal(t, rs.Result(), true) + require.Equal(t, true, rs.Result()) } diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index bcee45faf7..4621714379 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -5,8 +5,9 @@ import "fmt" // Assigment: let x = 5 type AssigmentState struct { params - prev Fsm - name string + bodyParams params + prev Fsm + name string //startedAt uint16 //ret uint16 //constant rideType @@ -24,11 +25,11 @@ func (a AssigmentState) backward(state Fsm) Fsm { } func (a AssigmentState) Property(name string) Fsm { - panic("AssigmentState Property") + return propertyTransition(a, a.bodyParams, name, a.d) } func (a AssigmentState) Func(name string, args []string, invoke string) Fsm { - return funcTransition(a, a.params, name, args, invoke) + return funcTransition(a, a.bodyParams, name, args, invoke) } func (a AssigmentState) Bytes(b []byte) Fsm { @@ -37,7 +38,7 @@ func (a AssigmentState) Bytes(b []byte) Fsm { } func (a AssigmentState) Condition() Fsm { - return conditionalTransition(a, a.params, a.d) + return conditionalTransition(a, a.bodyParams, a.d) } func (a AssigmentState) TrueBranch() Fsm { @@ -63,23 +64,29 @@ func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid, d return newAssigmentFsm(prev, params, name, n, d) } +func extendParams(p params) params { + p.r = newReferences(p.r) + return p +} + func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid, d Deferreds) Fsm { return AssigmentState{ - prev: prev, - params: p, - name: name, - n: n, - d: d, + prev: prev, + params: p, + bodyParams: extendParams(p), + name: name, + n: n, + d: d, } } // Create new scope, so assigment in assigment can't affect global state. func (a AssigmentState) Assigment(name string) Fsm { - params := a.params - params.r = newReferences(params.r) + //params := a.params + //params.r = newReferences(params.r) // TODO clear var in var n := a.params.u.next() - return assigmentFsmTransition(a, params, name, n, a.d) + return assigmentFsmTransition(a, a.bodyParams, name, n, a.d) } func (a AssigmentState) Return() Fsm { @@ -94,11 +101,11 @@ func (a AssigmentState) Long(value int64) Fsm { } func (a AssigmentState) Call(name string, argc uint16) Fsm { - return callTransition(a, a.params, name, argc, a.d) + return callTransition(a, a.bodyParams, name, argc, a.d) } func (a AssigmentState) Reference(name string) Fsm { - a.body = reference(a, a.params, name) + a.body = reference(a, a.bodyParams, name) return a } diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 8a9d69376f..d97952cc84 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -83,8 +83,9 @@ func newCallSystemFsm(prev Fsm, params params, name string, argc uint16, d Defer } func (a CallSystemState) Assigment(name string) Fsm { - //return assigmentFsmTransition(a, a.params, name) - panic("illegal transition") + n := a.params.u.next() + return assigmentFsmTransition(a, a.params, name, n, a.deferreds) + //panic(fmt.Sprintf("CallSystemState Assigment %s", a.params.txID)) } func (a CallSystemState) Long(value int64) Fsm { @@ -146,6 +147,4 @@ func (a CallSystemState) Write(_ params, b []byte) { panic(fmt.Sprintf("system function named `%s` not found", a.name)) } a.b.externalCall(n, a.argc) - //a.b.write(b) - //a.b.ret() } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 19bd25be46..92b0d076d4 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -15,6 +15,8 @@ type CallUserState struct { deferred []Deferred deferreds Deferreds + + rnode []RNode } func (a CallUserState) backward(state Fsm) Fsm { @@ -34,7 +36,7 @@ func newCallUserFsm(prev Fsm, params params, name string, argc uint16, d Deferre } func (a CallUserState) Property(name string) Fsm { - panic("CallUserState Property") + return propertyTransition(a, a.params, name, a.deferreds) } func (a CallUserState) Func(name string, args []string, invoke string) Fsm { @@ -70,7 +72,7 @@ func (a CallUserState) Boolean(v bool) Fsm { func (a CallUserState) Assigment(name string) Fsm { //return assigmentFsmTransition(a, a.params, name) - panic("illegal transition") + panic("CallUserState Assigment") } func (a CallUserState) Long(value int64) Fsm { @@ -150,15 +152,19 @@ func (a CallUserState) Write(_ params, b []byte) { var ns []uniqueid for i := uint16(0); i < a.argc; i++ { if n, ok := isConstant(a.deferred[i]); ok { - a.b.writeByte(OpSetArg) + a.b.writeByte(OpRef) a.b.write(encode(n)) + a.b.writeByte(OpCache) a.b.write(encode(fn + 1 + i)) + a.b.writeByte(OpPop) ns = append(ns, n) } else { n := a.u.next() - a.b.writeByte(OpSetArg) + a.b.writeByte(OpRef) a.b.write(encode(n)) + a.b.writeByte(OpCache) a.b.write(encode(fn + 1 + i)) + a.b.writeByte(OpPop) ns = append(ns, n) } } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 98845d14ff..43b1b28331 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -41,18 +41,17 @@ func (a ConditionalState) backward(v Fsm) Fsm { return a } -func (a ConditionalState) Property(string) Fsm { - panic("ConditionalState Property") +func (a ConditionalState) Property(name string) Fsm { + return propertyTransition(a, a.params, name, a.deferreds) } func (a ConditionalState) Func(name string, args []string, invoke string) Fsm { panic("Illegal call Func on ConditionalState") } -func (a ConditionalState) Bytes(b []byte) Fsm { - //a.rets = append(a.rets, a.params.b.len()) - //return constant(a, a.params, rideBytes(b)) - panic("") +func (a ConditionalState) Bytes(value []byte) Fsm { + a.deferred = append(a.deferred, a.constant(rideBytes(value))) + return a } func conditionalTransition(prev Fsm, params params, deferreds Deferreds) Fsm { diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 9dc3adf2aa..92f6268897 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -46,7 +46,12 @@ type FuncState struct { } func (a FuncState) backward(as Fsm) Fsm { - a.deferred = append(a.deferred, as.(Deferred)) + // Func in func. + if f, ok := as.(FuncState); ok { + a.defers.Add(as.(Deferred), f.n, fmt.Sprintf("func `%s`in func %s", f.name, a.name)) + } else { + a.deferred = append(a.deferred, as.(Deferred)) + } return a } @@ -139,14 +144,14 @@ func (a FuncState) FalseBranch() Fsm { panic("Illegal call `FalseBranch` on `FuncState`") } -func (a FuncState) Bytes(b []byte) Fsm { - //a.lastStmtOffset = a.b.len() - //return constant(a, a.params, rideBytes(b)) - panic("a") +func (a FuncState) Bytes(value []byte) Fsm { + a.deferred = append(a.deferred, a.constant(rideBytes(value))) + return a } -func (a FuncState) Func(name string, args []string, _ string) Fsm { - panic("Illegal call `Func` is `FuncState`") +func (a FuncState) Func(name string, args []string, invoke string) Fsm { + return funcTransition(a, a.params, name, args, invoke) + //panic(fmt.Sprintf("Illegal call `Func` is `FuncState` tx: %s", a.params.txID)) } func (a FuncState) Clean() { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 147c672e61..6997996279 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -44,7 +44,7 @@ func (a MainState) String(s string) Fsm { } type BuildExecutable interface { - BuildExecutable(version int) *Executable + BuildExecutable(version int, isDapp bool) *Executable } func NewMain(params params) Fsm { @@ -113,13 +113,14 @@ func (a MainState) Boolean(v bool) Fsm { return a } -func (a MainState) BuildExecutable(version int) *Executable { +func (a MainState) BuildExecutable(version int, isDapp bool) *Executable { startAt, code := a.b.build() return &Executable{ LibVersion: version, ByteCode: code, References: a.c.values, EntryPoints: map[string]uint16{"": startAt}, + IsDapp: isDapp, } } diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 894e7ed529..0009381666 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -56,6 +56,8 @@ type params struct { c *cell // Transaction ID, for debug purpose. txID string + // + rnode []RNode } func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) { diff --git a/pkg/ride/compiler_test.go b/pkg/ride/compiler_test.go deleted file mode 100644 index 558a662599..0000000000 --- a/pkg/ride/compiler_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package ride - -import ( - "encoding/base64" - "encoding/hex" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func c(values ...rideType) []rideType { - return values -} - -/* -func TestSimpleScriptsCompilation(t *testing.T) { - for _, test := range []struct { - comment string - source string - code string - constants []rideType - }{ - {`V1: true`, "AQa3b8tH", "0400", nil}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", "040002000001", c(rideInt(1))}, - {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", "040002000001", c(rideString("abc"))}, - {`V3: func A() = 1; func B() = 2; true`, "AwoBAAAAAUEAAAAAAAAAAAAAAAABCgEAAAABQgAAAAAAAAAAAAAAAAIG+N0aQQ==", - "04000200010102000001", c(rideInt(1), rideInt(2))}, - {`V3: func A() = 1; func B() = 2; A() != B()`, "AwoBAAAAAUEAAAAAAAAAAAAAAAABCgEAAAABQgAAAAAAAAAAAAAAAAIJAQAAAAIhPQAAAAIJAQAAAAFBAAAAAAkBAAAAAUIAAAAAv/Pmkg==", - "0a001400000a001000000900010002000200010102000001", c(rideInt(1), rideInt(2))}, - {`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", - "0c001509002700010c00110900030002000200010102000001", c(rideInt(1), rideString("string"))}, - {`V3: if true then if true then true else false else false`, "AwMGAwYGBwdYjCji", - "04070013030407000e03040600100305060015030500", nil}, - {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", - "0407000b030c001006000f030c00120004010501", nil}, - {`V3: if (let a = 1; a == 0) then {let a = 2; a == 0} else {let a = 0; a == 0}`, "AwMEAAAAAWEAAAAAAAAAAAEJAAAAAAAAAgUAAAABYQAAAAAAAAAAAAQAAAABYQAAAAAAAAAAAgkAAAAAAAACBQAAAAFhAAAAAAAAAAAABAAAAAFhAAAAAAAAAAAACQAAAAAAAAIFAAAAAWEAAAAAAAAAAAB3u9Yb", - "0c002a020001090003000207001d030c002e0200030900030002060029030c0032020005090003000200020000010200020102000401", c(rideInt(1), rideInt(0), rideInt(2), rideInt(0), rideInt(0), rideInt(0))}, - {`let a = 1; let b = a; let c = b; a == c`, - "AwQAAAABYQAAAAAAAAAAAQQAAAABYgUAAAABYQQAAAABYwUAAAABYgkAAAAAAAACBQAAAAFhBQAAAAFjUFI1Og==", - "0c00140c000c0900030002000c0010010c00140102000001", c(rideInt(1))}, - {`let x = addressFromString("3PJaDyprvekvPXPuAtxrapacuDJopgJRaU3"); let a = x; let b = a; let c = b; let d = c; let e = d; let f = e; f == e`, - "AQQAAAABeAkBAAAAEWFkZHJlc3NGcm9tU3RyaW5nAAAAAQIAAAAjM1BKYUR5cHJ2ZWt2UFhQdUF0eHJhcGFjdURKb3BnSlJhVTMEAAAAAWEFAAAAAXgEAAAAAWIFAAAAAWEEAAAAAWMFAAAAAWIEAAAAAWQFAAAAAWMEAAAAAWUFAAAAAWQEAAAAAWYFAAAAAWUJAAAAAAAAAgUAAAABZgUAAAABZS5FHzs=", - "0c000c0c00100900030002000c0010010c0014010c0018010c001c010c0020010c002401020000090037000101", c(rideString("3PJaDyprvekvPXPuAtxrapacuDJopgJRaU3"))}, - {`V3: let x = { let y = 1; y == 0 }; let y = { let z = 2; z == 0 } x == y`, - "AwQAAAABeAQAAAABeQAAAAAAAAAAAQkAAAAAAAACBQAAAAF5AAAAAAAAAAAABAAAAAF5BAAAAAF6AAAAAAAAAAACCQAAAAAAAAIFAAAAAXoAAAAAAAAAAAAJAAAAAAAAAgUAAAABeAUAAAABedn8HVg=", - "0c00200c001409000300020002000001020002010c00100200030900030002010c000c020001090003000201", c(rideInt(1), rideInt(0), rideInt(2), rideInt(0))}, - {`V3: let z = 0; let a = {let b = 1; b == z}; let b = {let c = 2; c == z}; a == b`, - "AwQAAAABegAAAAAAAAAAAAQAAAABYQQAAAABYgAAAAAAAAAAAQkAAAAAAAACBQAAAAFiBQAAAAF6BAAAAAFiBAAAAAFjAAAAAAAAAAACCQAAAAAAAAIFAAAAAWMFAAAAAXoJAAAAAAAAAgUAAAABYQUAAAABYnau3I8=", - "0c00200c001409000300020002000101020002010c00100c002c0900030002010c000c0c002c09000300020102000001", c(rideInt(0), rideInt(1), rideInt(2))}, - {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", - "0200010a001100010200020900030002000d000002000009000d0002070026030d000006002f030d0000090002000101", c(rideInt(0), rideInt(-10), rideInt(10))}, - {`V3: if (true) then {if (false) then {func XX() = true; XX()} else {func XX() = false; XX()}} else {if (true) then {let x = false; x} else {let x = true; x}}`, - "AwMGAwcKAQAAAAJYWAAAAAAGCQEAAAACWFgAAAAACgEAAAACWFgAAAAABwkBAAAAAlhYAAAAAAMGBAAAAAF4BwUAAAABeAQAAAABeAYFAAAAAXgYYeMi", - "0407001b0305070012030a002c0000060018030a002e000006002b0304070027030c003006002b030c0032000401050105010401", nil}, - {`tx.sender == Address(base58'11111111111111111')`, "AwkAAAAAAAACCAUAAAACdHgAAAAGc2VuZGVyCQEAAAAHQWRkcmVzcwAAAAEBAAAAEQAAAAAAAAAAAAAAAAAAAAAAWc7d/w==", - "0b00180800000200010900510001090003000200", c(rideString("sender"), rideBytes{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})}, - {`func b(x: Int) = {func a(y: Int) = x + y; a(1) + a(2)}; b(2) + b(3) == 0`, "AwoBAAAAAWIAAAABAAAAAXgKAQAAAAFhAAAAAQAAAAF5CQAAZAAAAAIFAAAAAXgFAAAAAXkJAABkAAAAAgkBAAAAAWEAAAABAAAAAAAAAAABCQEAAAABYQAAAAEAAAAAAAAAAAIJAAAAAAAAAgkAAGQAAAACCQEAAAABYgAAAAEAAAAAAAAAAAIJAQAAAAFiAAAAAQAAAAAAAAAAAwAAAAAAAAAAAPsZlhQ=", - "0200020a002a00010200030a002a000109000500020200040900030002000d00000d00000900050002010200000a001e00010200010a001e0001090005000201", c(rideInt(1), rideInt(2), rideInt(2), rideInt(3), rideInt(0))}, - {`func first(a: Int, b: Int) = {let x = a + b; x}; first(1, 2) == 0`, "AwoBAAAABWZpcnN0AAAAAgAAAAFhAAAAAWIEAAAAAXgJAABkAAAAAgUAAAABYQUAAAABYgUAAAABeAkAAAAAAAACCQEAAAAFZmlyc3QAAAACAAAAAAAAAAABAAAAAAAAAAACAAAAAAAAAAAAm+QHtw==", - "0200000200010a002000020200020900030002000d00000d00010900050002010c001401", c(rideInt(1), rideInt(2), rideInt(0))}, - {`func A(x: Int, y: Int) = {let r = x + y; r}; func B(x: Int, y: Int) = {let r = A(x, y); r}; B(1, 2) == 3`, "AwoBAAAAAUEAAAACAAAAAXgAAAABeQQAAAABcgkAAGQAAAACBQAAAAF4BQAAAAF5BQAAAAFyCgEAAAABQgAAAAIAAAABeAAAAAF5BAAAAAFyCQEAAAABQQAAAAIFAAAAAXgFAAAAAXkFAAAAAXIJAAAAAAAAAgkBAAAAAUIAAAACAAAAAAAAAAABAAAAAAAAAAACAAAAAAAAAAADSAdb8g==", - "0200000200010a002c00020200020900030002000d00000d00010900050002010d00000d00010a00300002010c0020010c001401", c(rideInt(1), rideInt(2), rideInt(3))}, - {`func f1(a: Int, b: Int) = a + b; func f2(a: Int, b: Int) = a - b; f2(f1(1, 2), 3) == 0`, "AwoBAAAAAmYxAAAAAgAAAAFhAAAAAWIJAABkAAAAAgUAAAABYQUAAAABYgoBAAAAAmYyAAAAAgAAAAFhAAAAAWIJAABlAAAAAgUAAAABYQUAAAABYgkAAAAAAAACCQEAAAACZjIAAAACCQEAAAACZjEAAAACAAAAAAAAAAABAAAAAAAAAAACAAAAAAAAAAADAAAAAAAAAAAALZ/RdA==", - "0200000200010a002800020200020a001c00020200030900030002000d00000d000109000b0002010d00000d0001090005000201", c(rideInt(1), rideInt(2), rideInt(3), rideInt(0))}, - {`func f1(a: Int, b: Int) = a + b; func f2(a: Int, b: Int) = a - b; let x = f1(1, 2); f2(x, 3) == 0`, "AwoBAAAAAmYxAAAAAgAAAAFhAAAAAWIJAABkAAAAAgUAAAABYQUAAAABYgoBAAAAAmYyAAAAAgAAAAFhAAAAAWIJAABlAAAAAgUAAAABYQUAAAABYgQAAAABeAkBAAAAAmYxAAAAAgAAAAAAAAAAAQAAAAAAAAAAAgkAAAAAAAACCQEAAAACZjIAAAACBQAAAAF4AAAAAAAAAAADAAAAAAAAAAAAr1ooAg==", - "0c00140200020a002000020200030900030002000200000200010a002c0002010d00000d000109000b0002010d00000d0001090005000201", c(rideInt(1), rideInt(2), rideInt(3), rideInt(0))}, - {`func f1(a: Int, b: Int) = a + b; func f2(a: Int, b: Int) = b; f2(f1(1, 2), 3) == 3`, "AwoBAAAAAmYxAAAAAgAAAAFhAAAAAWIJAABkAAAAAgUAAAABYQUAAAABYgoBAAAAAmYyAAAAAgAAAAFhAAAAAWIFAAAAAWIJAAAAAAAAAgkBAAAAAmYyAAAAAgkBAAAAAmYxAAAAAgAAAAAAAAAAAQAAAAAAAAAAAgAAAAAAAAAAAwAAAAAAAAAAA1cKYN4=", - "0200000200010a002000020200020a001c00020200030900030002000d0001010d00000d0001090005000201", c(rideInt(1), rideInt(2), rideInt(3), rideInt(3))}, - {`func f1(a: Int, b: Int) = a + b; func f2(a: Int, b: Int) = b; let x = f1(1, 2); f2(x, 3) == 3`, "AwoBAAAAAmYxAAAAAgAAAAFhAAAAAWIJAABkAAAAAgUAAAABYQUAAAABYgoBAAAAAmYyAAAAAgAAAAFhAAAAAWIFAAAAAWIEAAAAAXgJAQAAAAJmMQAAAAIAAAAAAAAAAAEAAAAAAAAAAAIJAAAAAAAAAgkBAAAAAmYyAAAAAgUAAAABeAAAAAAAAAAAAwAAAAAAAAAAA6avbPE=", - "0c00140200020a002000020200030900030002000200000200010a00240002010d0001010d00000d0001090005000201", c(rideInt(1), rideInt(2), rideInt(3), rideInt(3))}, - {`let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", - "0c001d0a001100010200020900030002000d000002000109000500020102000001", c(rideInt(1), rideInt(1), rideInt(2))}, - {`let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", - "0c00220a001100010200020900030002000d0000090020000102000109000500020102000001", c(rideBytes{0, 0, 0, 0, 0, 0, 0, 1}, rideInt(1), rideInt(2))}, - {`let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", - "0c00220a001100010200020900030002000d0000090020000102000109000500020102000001", c(rideBytes{0, 0, 0, 0, 0, 0, 0, 1}, rideInt(1), rideInt(2))}, - {`let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", - "0c00220a001100010200020900030002000c0022090020000102000109000500020102000001", c(rideBytes{0, 0, 0, 0, 0, 0, 0, 1}, rideInt(1), rideInt(2))}, - } { - src, err := base64.StdEncoding.DecodeString(test.source) - require.NoError(t, err, test.comment) - - tree, err := Parse(src) - require.NoError(t, err, test.comment) - assert.NotNil(t, tree, test.comment) - - rideScript, err := Compile(tree) - require.NoError(t, err, test.comment) - assert.NotNil(t, rideScript, test.comment) - script, ok := rideScript.(*SimpleScript) - require.True(t, ok, test.comment) - - code := hex.EncodeToString(script.Code) - assert.Equal(t, test.code, code, test.comment) - assert.ElementsMatch(t, test.constants, script.Constants, test.comment) - } -} -*/ - -func TestDAppScriptsCompilation(t *testing.T) { - for _, test := range []struct { - comment string - source string - code string - constants []rideType - entries map[string]callable - }{ - {`@Verifier(tx) func verify() = false`, "AAIDAAAAAAAAAAIIAQAAAAAAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAcysh6J", - "0500", nil, map[string]callable{"": {0, "tx"}}}, - {`let a = 1\n@Verifier(tx) func verify() = false`, "AAIDAAAAAAAAAAIIAQAAAAEAAAAAAWEAAAAAAAAAAAEAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAdVrdkQ", - "020000010500", c(rideInt(1)), map[string]callable{"": {4, "tx"}}}, - {`let a = 1\nfunc inc(v: Int) = {v + 1}\n@Verifier(tx) func verify() = false`, "AAIDAAAAAAAAAAIIAQAAAAIAAAAAAWEAAAAAAAAAAAEBAAAAA2luYwAAAAEAAAABdgkAAGQAAAACBQAAAAF2AAAAAAAAAAABAAAAAAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAHDMc8rg==", - "020000010d00000200010900050002010500", c(rideInt(1), rideInt(1)), map[string]callable{"": {16, "tx"}}}, - {`let a = 1\nfunc inc(v: Int) = {v + 1}\n@Verifier(tx) func verify() = inc(a) == 2`, "AAIDAAAAAAAAAAIIAQAAAAIAAAAAAWEAAAAAAAAAAAEBAAAAA2luYwAAAAEAAAABdgkAAGQAAAACBQAAAAF2AAAAAAAAAAABAAAAAAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAAAAAAAAgkBAAAAA2luYwAAAAEFAAAAAWEAAAAAAAAAAAJtD5WX", - "020000010d00000200010900050002010c00000a00040001020002090003000200", c(rideInt(1), rideInt(1), rideInt(2)), - map[string]callable{"": {16, "tx"}}}, - {`let a = 1\nlet b = 1\nfunc inc(v: Int) = {v + 1}\nfunc add(x: Int, y: Int) = {x + y}\n@Verifier(tx) func verify() = inc(a) == add(a, b)`, "AAIDAAAAAAAAAAIIAQAAAAQAAAAAAWEAAAAAAAAAAAEAAAAAAWIAAAAAAAAAAAEBAAAAA2luYwAAAAEAAAABdgkAAGQAAAACBQAAAAF2AAAAAAAAAAABAQAAAANhZGQAAAACAAAAAXgAAAABeQkAAGQAAAACBQAAAAF4BQAAAAF5AAAAAAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAAAAAAAAgkBAAAAA2luYwAAAAEFAAAAAWEJAQAAAANhZGQAAAACBQAAAAFhBQAAAAFiDbIkmw==", - "02000001020001010d00000200020900050002010d00000d00010900050002010c00000a000800010c00000c00040a00140002090003000200", - c(rideInt(1), rideInt(1), rideInt(1)), - map[string]callable{"": {32, "tx"}}}, - {`let a = 1\nlet b = 1\nlet messages = ["INFO", "WARN"]\nfunc inc(v: Int) = {v + 1}\nfunc add(x: Int, y: Int) = {x + y}\nfunc msg(i: Int) = {messages[i]}\n@Verifier(tx) func verify() = if inc(a) == add(a, b) then throw(msg(a)) else throw(msg(b))`, "AAIDAAAAAAAAAAIIAQAAAAYAAAAAAWEAAAAAAAAAAAEAAAAAAWIAAAAAAAAAAAEAAAAACG1lc3NhZ2VzCQAETAAAAAICAAAABElORk8JAARMAAAAAgIAAAAEV0FSTgUAAAADbmlsAQAAAANpbmMAAAABAAAAAXYJAABkAAAAAgUAAAABdgAAAAAAAAAAAQEAAAADYWRkAAAAAgAAAAF4AAAAAXkJAABkAAAAAgUAAAABeAUAAAABeQEAAAADbXNnAAAAAQAAAAFpCQABkQAAAAIFAAAACG1lc3NhZ2VzBQAAAAFpAAAAAAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAADCQAAAAAAAAIJAQAAAANpbmMAAAABBQAAAAFhCQEAAAADYWRkAAAAAgUAAAABYQUAAAABYgkAAAIAAAABCQEAAAADbXNnAAAAAQUAAAABYQkAAAIAAAABCQEAAAADbXNnAAAAAQUAAAABYvi7IpM=", - "02000001020001010200020200030b001609001e000209001e0002010d00000200040900050002010d00000d00010900050002010c00080d00000900320002010c00000a001c00010c00000c00040a00280002090003000207006c030c00000a00340001090028000106007a030c00040a00340001090028000100", - c(rideInt(1), rideInt(1), rideString("INFO"), rideString("WARN"), rideInt(1)), - map[string]callable{"": {64, "tx"}}}, - {`@Callable(i)func f() = {WriteSet([DataEntry("YYY", "XXX")]}`, "AAIDAAAAAAAAAAQIARIAAAAAAAAAAAEAAAABaQEAAAABZgAAAAAJAQAAAAhXcml0ZVNldAAAAAEJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAAA1lZWQIAAAADWFhYBQAAAANuaWwAAAAAeFguLA==", - "02000002000109005600020b001609001e000209006e000100", c(rideString("YYY"), rideString("XXX")), - map[string]callable{"f": {0, "i"}}}, - {`@Callable(i)func f() = {let callerAddress = toBase58String(i.caller.bytes); WriteSet([DataEntry(callerAddress, "XXX")]}`, "AAIDAAAAAAAAAAQIARIAAAAAAAAAAAEAAAABaQEAAAABZgAAAAAEAAAADWNhbGxlckFkZHJlc3MJAAJYAAAAAQgIBQAAAAFpAAAABmNhbGxlcgAAAAVieXRlcwkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAANY2FsbGVyQWRkcmVzcwIAAAADWFhYBQAAAANuaWwAAAAAe3xtyw==", - "0d000008000008000109003d0001010c000002000209005600020b001609001e000209006e000100", - c(rideString("caller"), rideString("bytes"), rideString("XXX")), - map[string]callable{"f": {15, "i"}}}, - {`let messages = ["INFO", "WARN"]\nfunc msg(i: Int) = {messages[i]}\n@Callable(i)func tellme(x: Int) = {WriteSet([DataEntry("m", msg(x))]}`, "AAIDAAAAAAAAAAcIARIDCgEBAAAAAgAAAAAIbWVzc2FnZXMJAARMAAAAAgIAAAAESU5GTwkABEwAAAACAgAAAARXQVJOBQAAAANuaWwBAAAAA21zZwAAAAEAAAABaQkAAZEAAAACBQAAAAhtZXNzYWdlcwUAAAABaQAAAAEAAAABaQEAAAAGdGVsbG1lAAAAAQAAAAF4CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFtCQEAAAADbXNnAAAAAQUAAAABeAUAAAADbmlsAAAAAO4TltI=", - "0200000200010b001609001e000209001e0002010c00000d00000900320002010200020d00010a0014000109005600020b001609001e000209006e000100", c(rideString("INFO"), rideString("WARN"), rideString("m")), - map[string]callable{"tellme": {32, "i"}}}, - {`let messages = ["INFO", "WARN"]\nfunc msg(i: Int) = {messages[i]}\n@Callable(i)func tellme(x: Int, y: Int) = {WriteSet([DataEntry("m", msg(x))]}`, "AAIDAAAAAAAAAAgIARIECgIBAQAAAAIAAAAACG1lc3NhZ2VzCQAETAAAAAICAAAABElORk8JAARMAAAAAgIAAAAEV0FSTgUAAAADbmlsAQAAAANtc2cAAAABAAAAAWkJAAGRAAAAAgUAAAAIbWVzc2FnZXMFAAAAAWkAAAABAAAAAWkBAAAABnRlbGxtZQAAAAIAAAABeAAAAAF5CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFtCQEAAAADbXNnAAAAAQUAAAABeAUAAAADbmlsAAAAAD8Tlfs=", - "0200000200010b001609001e000209001e0002010c00000d00000900320002010200020d00010a0014000109005600020b001609001e000209006e000100", c(rideString("INFO"), rideString("WARN"), rideString("m")), - map[string]callable{"tellme": {32, "i"}}}, - {`let a = 1; let messages = ["INFO", "WARN"]; func msg(i: Int) = {messages[i]}; @Callable(i)func tellme(x: Int) = {let m = msg(x); let callerAddress = toBase58String(i.caller.bytes); WriteSet([DataEntry(callerAddress + "-m", m)]}`, "AAIDAAAAAAAAAAcIARIDCgEBAAAAAwAAAAABYQAAAAAAAAAAAQAAAAAIbWVzc2FnZXMJAARMAAAAAgIAAAAESU5GTwkABEwAAAACAgAAAARXQVJOBQAAAANuaWwBAAAAA21zZwAAAAEAAAABaQkAAZEAAAACBQAAAAhtZXNzYWdlcwUAAAABaQAAAAEAAAABaQEAAAAGdGVsbG1lAAAAAQAAAAF4BAAAAAFtCQEAAAADbXNnAAAAAQUAAAABeAQAAAANY2FsbGVyQWRkcmVzcwkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzCQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACCQABLAAAAAIFAAAADWNhbGxlckFkZHJlc3MCAAAAAi1tBQAAAAFtBQAAAANuaWwAAAAAgveN3A==", - "020000010200010200020b001609001e000209001e0002010c00040d00000900320002010d000008000308000409003d0001010d00010a00180001010c002402000509002d00020c003309005600020b001609001e000209006e000100", c(rideInt(1), rideString("INFO"), rideString("WARN"), rideString("caller"), rideString("bytes"), rideString("-m")), - map[string]callable{"tellme": {60, "i"}}}, - } { - src, err := base64.StdEncoding.DecodeString(test.source) - require.NoError(t, err, test.comment) - - tree, err := Parse(src) - require.NoError(t, err, test.comment) - assert.NotNil(t, tree, test.comment) - - rideScript, err := Compile(tree) - require.NoError(t, err, test.comment) - assert.NotNil(t, rideScript, test.comment) - script, ok := rideScript.(*DAppScript) - require.True(t, ok, test.comment) - - code := hex.EncodeToString(script.Code) - assert.Equal(t, test.code, code, test.comment) - assert.ElementsMatch(t, test.constants, script.Constants, test.comment) - assert.Equal(t, test.entries, script.EntryPoints, test.comment) - } -} diff --git a/pkg/ride/errors.go b/pkg/ride/errors.go new file mode 100644 index 0000000000..62f260e732 --- /dev/null +++ b/pkg/ride/errors.go @@ -0,0 +1,20 @@ +package ride + +import "github.com/pkg/errors" + +type ThrowError struct { + msg string +} + +func NewThrowError(msg string) *ThrowError { + return &ThrowError{msg: msg} +} + +func (a *ThrowError) Error() string { + return a.msg +} + +func IsThrowErr(err error) bool { + _, ok := errors.Cause(err).(*ThrowError) + return ok +} diff --git a/pkg/ride/errors_test.go b/pkg/ride/errors_test.go new file mode 100644 index 0000000000..6047e4d4fc --- /dev/null +++ b/pkg/ride/errors_test.go @@ -0,0 +1,14 @@ +package ride_test + +import ( + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + "github.com/wavesplatform/gowaves/pkg/ride" +) + +func TestIsThrowErr(t *testing.T) { + require.False(t, ride.IsThrowErr(errors.New(""))) + require.True(t, ride.IsThrowErr(ride.NewThrowError(""))) +} diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 41705b371d..f3c64b4ca1 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -10,6 +10,7 @@ type Executable struct { ByteCode []byte EntryPoints map[string]uint16 References map[uniqueid]point + IsDapp bool } func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (RideResult, error) { @@ -22,6 +23,11 @@ func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (Rid return nil, err } switch tv := v.(type) { + case rideThrow: + if a.IsDapp { + return DAppResult{res: false, msg: string(tv), calls: vm.calls}, nil + } + return ScriptResult{res: false, msg: string(tv), calls: vm.calls}, nil case rideBoolean: return ScriptResult{res: bool(tv), operations: vm.numOperations, calls: vm.calls}, nil case rideObject: diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index d883f071d1..52939659b7 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -35,13 +35,21 @@ func retRideType() rideList { return nil } +func lastBlock(env RideEnvironment, _ ...rideType) (rideType, error) { + return env.block(), nil +} + var predefinedFunctions = map[string]predefFunc{ - "tx": {id: math.MaxUint16 - 0, f: tx}, - "unit": {id: math.MaxUint16 - 1, f: unit}, - "NOALG": {id: math.MaxUint16 - 2, f: createNoAlg}, - "this": {id: math.MaxUint16 - 3, f: this}, - "height": {id: math.MaxUint16 - 4, f: height}, - "nil": {id: math.MaxUint16 - 5, f: nilFunc}, + "tx": {id: math.MaxUint16 - 0, f: tx}, + "unit": {id: math.MaxUint16 - 1, f: unit}, + "NOALG": {id: math.MaxUint16 - 2, f: createNoAlg}, + "this": {id: math.MaxUint16 - 3, f: this}, + "height": {id: math.MaxUint16 - 4, f: height}, + "nil": {id: math.MaxUint16 - 5, f: nilFunc}, + "lastBlock": {id: math.MaxUint16 - 6, f: lastBlock}, + "UP": {id: math.MaxUint16 - 7, f: createUp}, + "DOWN": {id: math.MaxUint16 - 8, f: createDown}, + "HALFDOWN": {id: math.MaxUint16 - 9, f: createHalfDown}, } var predefined *predef diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index fbf2eb8917..89760854e8 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -91,7 +91,7 @@ func CallFunction2(txID string, env RideEnvironment, tree *Tree, name string, ar if name == "" { name = "default" } - f, numArgs, err := CompileFunction(txID, tree, name, args) + f, numArgs, err := CompileFunction(txID, tree, name, args, tree.IsDApp()) if err != nil { return nil, err } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 0a2a660f09..c2d0e83738 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -8,6 +8,8 @@ import ( const limitOperations = 50000 +var throwErr = errors.New("throw") + type vm struct { env RideEnvironment code []byte @@ -118,7 +120,8 @@ func (m *vm) run() (rideType, error) { return nil, errors.Wrapf(err, "iteration %d", m.numOperations) } if isThrow(res) { - return nil, errors.Errorf("terminated execution by throw with message %q on iteration %d", res, m.numOperations) + return res, nil + //return nil, errors.Wrapf(throwErr, "terminated execution by throw with message %q on iteration %d", res, m.numOperations) } m.push(res) case OpReturn: From 415c5c1add2833a29ae708a89115006a71c51f0b Mon Sep 17 00:00:00 2001 From: Frozen Date: Wed, 23 Dec 2020 17:32:54 +0300 Subject: [PATCH 26/55] Fix transitions. --- pkg/ride/reverse_tree.go | 70 ++++++++++++++++++++++++++++++-- pkg/ride/reverse_tree_test.go | 43 ++++++++++++++++++++ pkg/ride/reversed_tree.go | 27 +++++++++++- pkg/ride/tree_evaluation_test.go | 8 ++-- 4 files changed, 140 insertions(+), 8 deletions(-) diff --git a/pkg/ride/reverse_tree.go b/pkg/ride/reverse_tree.go index 3609f9265c..2eaae585bd 100644 --- a/pkg/ride/reverse_tree.go +++ b/pkg/ride/reverse_tree.go @@ -1,6 +1,8 @@ package ride -import "fmt" +import ( + "fmt" +) func ReverseTree(n []Node) { for i := len(n) - 1; i >= 0; i-- { @@ -8,8 +10,8 @@ func ReverseTree(n []Node) { } } +/* func reverseTree(n Node, r []*RLet) RNode { - switch v := n.(type) { case *FunctionDeclarationNode: return &RFunc{ @@ -42,8 +44,8 @@ func reverseTree(n Node, r []*RLet) RNode { default: panic(fmt.Sprintf("unknown type %T", n)) } - } +*/ // //func walkAssigments(n Node, r []*RLet) ([]*RLet, Node) { @@ -59,3 +61,65 @@ func reverseTree(n Node, r []*RLet) RNode { // return r, v // } //} + +//func compileReverse(r RNode, out *bytes.Buffer) { +// switch t := r.(type) { +// case *RCall: +// for i, v := range reverseCallTree(t.CallTree()) { +// +// } +// +// out.Write() +// } +// +//} + +//func compileArguments(call *RCall, out *bytes.Buffer) { +// d := []RNode{ +// call, +// } +// for i := len(call.Arguments) - 1; i >= 0; i-- { +// switch call.Arguments[i].(type) { +// case *RLong: +// d = append(d, RLong{}) +// } +// } +//} + +func reverseTree2(n Node, out []RNode, deferreds []RNode) []RNode { + switch t := n.(type) { + case *FunctionDeclarationNode: + out = append(out, &RFunc{Name: t.Name, Arguments: t.Arguments, Invocation: t.invocationParameter}) + return reverseTree2(t.Body, out, nil) + case *AssignmentNode: + return reverseTree2(t.Block, out, append(deferreds, &RLet{Name: t.Name, Body: reverseTree2(t.Expression, nil, nil)})) + case *LongNode: + return append(out, &RLong{Value: t.Value}) + case *FunctionCallNode: + out = append(out, reverseRnodes(flatCall(t))...) + return append(out, deferreds...) + default: + panic(fmt.Sprintf("unknown type %T", n)) + } +} + +func flatCall(call *FunctionCallNode) []RNode { + out := []RNode{ + &RCall{ + Name: call.Name, + }, + } + for i := len(call.Arguments) - 1; i >= 0; i-- { + switch t := call.Arguments[i].(type) { + case *LongNode: + out = append(out, &RLong{Value: t.Value}) + case *FunctionCallNode: + out = append(out, flatCall(t)...) + case *ReferenceNode: + out = append(out, &RRef{Name: t.Name}) + default: + panic(fmt.Sprintf("unknown type %T", call.Arguments[i])) + } + } + return out +} diff --git a/pkg/ride/reverse_tree_test.go b/pkg/ride/reverse_tree_test.go index 9805488109..f026c65442 100644 --- a/pkg/ride/reverse_tree_test.go +++ b/pkg/ride/reverse_tree_test.go @@ -13,6 +13,7 @@ func abc(key: String) = { x + y } */ +/* func TestReverseFunc(t *testing.T) { n := &FunctionDeclarationNode{ Name: "abc", @@ -55,6 +56,8 @@ func TestReverseFunc(t *testing.T) { } +*/ + /* func abc(key: String) = { match getInteger(this, key) { @@ -64,6 +67,7 @@ func abc(key: String) = { 0 } */ +/* func TestReverseFunc2(t *testing.T) { n := &FunctionDeclarationNode{ Name: "abc", @@ -137,5 +141,44 @@ func TestReverseFunc2(t *testing.T) { // }, //}, }, rs) +} +*/ +/* +func abc(key: String) = { + let x = 1 + let y = 2 + x + y +} +*/ +func TestReverse2(t *testing.T) { + n := &FunctionDeclarationNode{ + Name: "abc", + Arguments: []string{"key"}, + Body: &AssignmentNode{ + Name: "x", + Expression: &LongNode{Value: 1}, + Block: &AssignmentNode{ + Name: "y", + Expression: &LongNode{Value: 2}, + Block: &FunctionCallNode{ + Name: "+", + Arguments: []Node{ + &ReferenceNode{Name: "x"}, + &ReferenceNode{Name: "y"}, + }, + }, + }, + }, + } + rs := reverseTree2(n, nil, nil) + + require.Equal(t, []RNode{ + &RFunc{Invocation: "", Name: "abc", Arguments: []string{"key"}}, + &RRef{Name: "x"}, + &RRef{Name: "y"}, + &RCall{Name: "+"}, + &RLet{Name: "x", Body: []RNode{&RLong{Value: 1}}}, + &RLet{Name: "y", Body: []RNode{&RLong{Value: 2}}}, + }, rs) } diff --git a/pkg/ride/reversed_tree.go b/pkg/ride/reversed_tree.go index 062183db18..c2c804bf0a 100644 --- a/pkg/ride/reversed_tree.go +++ b/pkg/ride/reversed_tree.go @@ -16,7 +16,7 @@ func (a *RFunc) RNode() {} type RLet struct { Name string //N uniqueid - Body RNode + Body []RNode } func (a *RLet) RNode() {} @@ -39,6 +39,31 @@ type RCall struct { func (a *RCall) RNode() {} +func reverseRnodes(a []RNode) []RNode { + out := make([]RNode, len(a)) + for i := 0; i < len(a); i++ { + out[len(a)-1-i] = a[i] + } + return out +} + +func (a *RCall) CallTree() []RNode { + d := []RNode{ + a, + } + for i := len(a.Arguments) - 1; i >= 0; i-- { + switch t := a.Arguments[i].(type) { + case *RLong: + d = append(d, a.Arguments[i]) + case *RCall: + d = append(d, t.CallTree()...) + default: + panic("") + } + } + return d +} + type RRef struct { Name string Assigments []*RLet diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 339f445cc0..9e08ecb407 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -2884,7 +2884,7 @@ func TestNoDeclaration(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "settle", arguments) + res, err := CallFunction("", env, tree, "settle", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -3071,7 +3071,7 @@ func TestZeroReissue(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "replenishment", arguments) + res, err := CallFunction("", env, tree, "replenishment", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -3291,7 +3291,7 @@ func TestStageNet2(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "purchaseToken", arguments) + res, err := CallFunction("", env, tree, "purchaseToken", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -3375,7 +3375,7 @@ func TestRecipientAddressToString(t *testing.T) { checkMessageLengthFunc: v3check, } - res, err := CallVerifier(env, tree) + res, err := CallVerifier("", env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) From b43481d3af1f06996f240b61f759019907460f50 Mon Sep 17 00:00:00 2001 From: Frozen Date: Wed, 23 Dec 2020 19:10:07 +0300 Subject: [PATCH 27/55] Fix functions. --- pkg/ride/compiler2.go | 19 ------------------- pkg/ride/executable.go | 8 +++++++- pkg/ride/functions_predefined.go | 16 ++++++++-------- pkg/ride/tree_evaluation.go | 11 +++++++---- pkg/ride/tree_evaluation_test.go | 29 ++++++++++++++--------------- pkg/ride/vm_test.go | 3 ++- 6 files changed, 38 insertions(+), 48 deletions(-) diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index c4d6d9b4c1..64f93f229b 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -216,25 +216,6 @@ func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool) (*E params.addPredefined(k, v.id, v.f) } - //invokParam := nodes[len(nodes)-1].(*FunctionDeclarationNode).invocationParameter - //if invokParam != "" { - // params.r.set( - // invokParam, - // math.MaxUint16, - // ) - //} - - //for _, arg := range args { - // params.r.set( - // arg.name, - // params.constant(arg.arg), - // ) - ////} - //args2 := make([]rideType, len(args)) - //for i := range args { - // args2[i] = args[i].arg - //} - f := NewMain(params) for _, node := range nodes { zap.S().Error(Decompiler(node)) diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index f3c64b4ca1..873d9821e0 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -1,6 +1,8 @@ package ride import ( + "io" + "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" ) @@ -71,10 +73,14 @@ func (a *Executable) makeVm(environment RideEnvironment, arguments []rideType) ( return &vm{ code: a.ByteCode, ip: int(a.EntryPoints[""]), - functions: mergeWithPredefined(fSelect, predefined), + functions: fSelect, functionName: provider, env: environment, ref: a.References, stack: arguments, }, nil } + +func (a *Executable) WriteTo(w io.Writer) (int64, error) { + panic("Executable WriteTo") +} diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index 52939659b7..df339feadb 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -9,14 +9,14 @@ func tx(env RideEnvironment, _ ...rideType) (rideType, error) { return env.transaction(), nil } -func mergeWithPredefined(f func(id int) rideFunction, p *predef) func(id int) rideFunction { - return func(id int) rideFunction { - if c := p.getn(id); c != nil { - return c - } - return f(id) - } -} +//func mergeWithPredefined(f func(id int) rideFunction, p *predef) func(id int) rideFunction { +// return func(id int) rideFunction { +// if c := p.getn(id); c != nil { +// return c +// } +// return f(id) +// } +//} func this(env RideEnvironment, _ ...rideType) (rideType, error) { return env.this(), nil diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 89760854e8..cb8f8b975a 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -6,7 +6,7 @@ import ( "go.uber.org/zap" ) -func CallVerifier2(env RideEnvironment, tree *Tree) (RideResult, error) { +func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { e, err := treeVerifierEvaluator(env, tree) if err != nil { return nil, errors.Wrap(err, "failed to call verifier") @@ -19,6 +19,9 @@ func CallVerifier3(txID string, env RideEnvironment, tree *Tree) (RideResult, er if err != nil { return nil, errors.Wrap(err, "call compile script") } + if env == nil { + return nil, errors.Errorf("env is nil") + } return compiled.Run(env, []rideType{env.transaction()}) } @@ -28,7 +31,7 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, err return nil, err } - r2, err := CallVerifier2(env, tree) + r2, err := CallTreeVerifier(env, tree) if err != nil { return nil, err } @@ -58,7 +61,7 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, err return r, nil } -func CallFunction3(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { +func CallTreeFunction(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { if name == "" { name = "default" } @@ -70,7 +73,7 @@ func CallFunction3(env RideEnvironment, tree *Tree, name string, args proto.Argu } func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - rs1, err := CallFunction3(env, tree, name, args) + rs1, err := CallTreeFunction(env, tree, name, args) if err != nil { return nil, errors.Wrap(err, "call function by tree") } diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 9e08ecb407..4839fdd1b1 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -57,7 +57,6 @@ func TestSimpleScriptEvaluation(t *testing.T) { {`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, {`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, - {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, {`V4: if tx.proofs[0] != base58'' then tx.proofs[1] == base58'' else false`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, @@ -82,7 +81,7 @@ func TestSimpleScriptEvaluation(t *testing.T) { require.NoError(t, err, test.comment) assert.NotNil(t, tree, test.comment) - res, err := CallVerifier("", test.env, tree) + res, err := CallTreeVerifier(test.env, tree) require.NoError(t, err, test.comment) require.NotNil(t, res, test.comment) @@ -330,7 +329,7 @@ func TestFunctionsEvaluation(t *testing.T) { require.NoError(t, err, test.name) assert.NotNil(t, tree, test.name) - res, err := CallVerifier("", test.env, tree) + res, err := CallTreeVerifier(test.env, tree) if test.error { assert.Error(t, err, "No error in "+test.name) } else { @@ -360,7 +359,7 @@ func TestOverlapping(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", nil, tree) + res, err := CallTreeVerifier(nil, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -383,7 +382,7 @@ func TestUserFunctionsInExpression(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", nil, tree) + res, err := CallTreeVerifier(nil, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -1577,7 +1576,7 @@ func TestLigaDApp1(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "stage2", proto.Arguments{}) + res, err := CallTreeFunction(env, tree, "stage2", proto.Arguments{}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1761,7 +1760,7 @@ func TestLigaDApp1(t *testing.T) { }, } - res, err = CallFunction("", env, tree, "stage31", args2) + res, err = CallTreeFunction(env, tree, "stage31", args2) require.NoError(t, err) r, ok = res.(DAppResult) require.True(t, ok) @@ -2003,7 +2002,7 @@ func TestDropElementDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "dropElementInArray", arguments) + res, err := CallTreeFunction(env, tree, "dropElementInArray", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2117,7 +2116,7 @@ func TestMathDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "coxRossRubinsteinCall", arguments) + res, err := CallTreeFunction(env, tree, "coxRossRubinsteinCall", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2535,7 +2534,7 @@ func TestAssetInfoV3V4(t *testing.T) { require.NoError(t, err) assert.NotNil(t, treeV3) - res, err := CallVerifier("", env, treeV3) + res, err := CallTreeVerifier(env, treeV3) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -2556,7 +2555,7 @@ func TestAssetInfoV3V4(t *testing.T) { require.NoError(t, err) assert.NotNil(t, treeV3) - res, err = CallVerifier("", env, treeV4) + res, err = CallTreeVerifier(env, treeV4) require.NoError(t, err) r, ok = res.(ScriptResult) require.True(t, ok) @@ -2572,7 +2571,7 @@ func TestJSONParsing(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", nil, tree) + res, err := CallTreeVerifier(nil, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -2594,7 +2593,7 @@ func TestDAppWithFullIssue(t *testing.T) { return rideBytes(id) }, } - res, err := CallFunction("", env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) + res, err := CallTreeFunction(env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2620,7 +2619,7 @@ func TestDAppWithSimpleIssue(t *testing.T) { return rideBytes(id) }, } - res, err := CallFunction("", env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) + res, err := CallTreeFunction(env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2884,7 +2883,7 @@ func TestNoDeclaration(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "settle", arguments) + res, err := CallTreeFunction(env, tree, "settle", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) diff --git a/pkg/ride/vm_test.go b/pkg/ride/vm_test.go index c6d0eb2dac..ad41be5bd3 100644 --- a/pkg/ride/vm_test.go +++ b/pkg/ride/vm_test.go @@ -19,6 +19,7 @@ import ( //go:generate moq -pkg ride -out types_moq_test.go ../types SmartState:MockSmartState +/* func TestExecution(t *testing.T) { //state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { // return testTransferWithProofs(), nil @@ -88,7 +89,7 @@ func TestExecution(t *testing.T) { assert.Equal(t, test.res, r.Result(), test.comment) } } - +*/ func newTransferTransaction() *proto.TransferWithProofs { js := `{"type":4,"version":2,"id":"CqjGMbrd5bFmLAv2mUSdphEJSgVWkWa6ZtcMkKmgH2ax","proofs":["5W7hjPpgmmhxevCt4A7y9F8oNJ4V9w2g8jhQgx2qGmBTNsP1p1MpQeKF3cvZULwJ7vQthZfSx2BhL6TWkHSVLzvq"],"senderPublicKey":"14ovLL9a6xbBfftyxGNLKMdbnzGgnaFQjmgUJGdho6nY","assetId":null,"feeAssetId":null,"timestamp":1544715621,"amount":15,"fee":10000,"recipient":"3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"}` tv2 := &proto.TransferWithProofs{} From f755658a707bae377149c588c2d03e84f94f12e6 Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 24 Dec 2020 15:31:27 +0300 Subject: [PATCH 28/55] Fix functions. --- pkg/ride/compiler2.go | 2 +- pkg/ride/compiler_call_user.go | 2 +- pkg/ride/compiler_func.go | 5 +-- pkg/ride/compiler_helpers.go | 12 +++--- pkg/ride/compiler_main.go | 2 +- pkg/ride/compiler_property.go | 2 +- pkg/ride/compiler_state.go | 39 ++---------------- pkg/ride/tree_evaluation.go | 73 +++++++++++++++++----------------- pkg/ride/vm.go | 5 ++- 9 files changed, 55 insertions(+), 87 deletions(-) diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 64f93f229b..27a5c808a3 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -213,7 +213,7 @@ func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool) (*E txID: txID, } for k, v := range predefinedFunctions { - params.addPredefined(k, v.id, v.f) + params.addPredefined(k, v.id, v.id) } f := NewMain(params) diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 92b0d076d4..79f317a2ca 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -182,7 +182,7 @@ func (a CallUserState) Write(_ params, b []byte) { if _, ok := isConstant(b); ok { // skip right now } else { - a.c.set(ns[i], nil, nil, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i)) + a.c.set(ns[i], nil, 0, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i)) b.Write(a.params, nil) a.b.ret() } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 92f6268897..29ff8473d8 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -160,8 +160,7 @@ func (a FuncState) Clean() { func (a FuncState) Write(_ params, b []byte) { pos := a.b.len() - a.params.c.set(a.n, nil, nil, pos, false, fmt.Sprintf("function %s", a.name)) - //writeDeferred(a.params, a.deferred) + a.params.c.set(a.n, nil, 0, pos, false, fmt.Sprintf("function %s", a.name)) if len(a.deferred) != 1 { panic("len(a.deferred) != 1") } @@ -175,7 +174,7 @@ func (a FuncState) Write(_ params, b []byte) { for _, v := range a.defers.Get() { pos := a.b.len() - a.c.set(v.uniq, nil, nil, pos, false, v.debug) + a.c.set(v.uniq, nil, 0, pos, false, 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 b85190ee7c..36403df9b8 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -93,11 +93,11 @@ func (b *builder) write(i []byte) { } type point struct { - position uint16 `cbor:"0,keyasint"` - value rideType `cbor:"1,keyasint"` - fn rideFunction `cbor:"-"` - constant bool `cbor:"2,keyasint"` - debugInfo string `cbor:"3,keyasint"` + position uint16 `cbor:"0,keyasint"` + value rideType `cbor:"1,keyasint"` + fn uint16 `cbor:"2,keyasint"` + constant bool `cbor:"3,keyasint"` + debugInfo string `cbor:"4,keyasint"` } type cell struct { @@ -110,7 +110,7 @@ func newCell() *cell { } } -func (a *cell) set(u uniqueid, result rideType, fn rideFunction, position uint16, constant bool, debug string) { +func (a *cell) set(u uniqueid, result rideType, fn uint16, position uint16, constant bool, debug string) { a.values[u] = point{ position: position, value: result, diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 6997996279..45837491f2 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -88,7 +88,7 @@ func (a MainState) Return() Fsm { for _, v := range a.deferreds.Get() { pos := a.b.len() - a.c.set(v.uniq, nil, nil, pos, false, v.debug) + a.c.set(v.uniq, nil, 0, pos, false, 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 ee9d95c0b5..cef818bef3 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -96,7 +96,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), nil, 0, true, fmt.Sprintf("property?? %s", a.name)) + a.c.set(next, rideString(a.name), 0, 0, true, 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 0009381666..0ba40d1f28 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -60,51 +60,18 @@ type params struct { rnode []RNode } -func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) { +func (a *params) addPredefined(name string, id uniqueid, fn uint16) { a.r.set(name, id) a.c.set(id, nil, fn, 0, false, name) } func (a *params) constant(value rideType) constantDeferred { n := a.u.next() - a.c.set(n, value, nil, 0, true, fmt.Sprintf("constant %q", value)) + a.c.set(n, value, 0, 0, true, fmt.Sprintf("constant %q", value)) return NewConstantDeferred(n) } -//func long(f Fsm, params params, value int64) Fsm { -// params.b.push(params.constant(rideInt(value))) -// return f -//} - -//func boolean(f Fsm, params params, value bool) Deferred { -// return NewDeferred(func() { -// params.b.push(params.constant(rideBoolean(value))) -// }, nil) -// //return f -//} - -//func bts(f Fsm, params params, value []byte) Fsm { -// params.b.push(params.constant(rideBytes(value))) -// return f -//} - -//func str(a Fsm, params params, value string) Deferred { -// return NewDeferred(func() { -// params.b.push(params.constant(rideString(value))) -// }, nil) -//} - -//func constant(a Fsm, params params, value rideType) Fsm { -// params.b.push(params.constant(value)) -// return a -//} - -//func putConstant(params params, rideType rideType) uniqueid { -// index := params.constant(rideType) -// return index -//} - -func reference(f Fsm, params params, name string) Deferred { +func reference(_ Fsm, params params, name string) Deferred { pos, ok := params.r.get(name) if !ok { panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index cb8f8b975a..358ba1ef1f 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -3,7 +3,6 @@ package ride import ( "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" - "go.uber.org/zap" ) func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { @@ -14,7 +13,7 @@ func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { return e.evaluate() } -func CallVerifier3(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { +func CallVmVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { compiled, err := CompileVerifier(txID, tree) if err != nil { return nil, errors.Wrap(err, "call compile script") @@ -26,38 +25,40 @@ func CallVerifier3(txID string, env RideEnvironment, tree *Tree) (RideResult, er } func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { - r, err := CallVerifier3(txID, env, tree) + r, err := CallVmVerifier(txID, env, tree) if err != nil { return nil, err } - r2, err := CallTreeVerifier(env, tree) - if err != nil { - return nil, err - } - if !r.Eq(r2) { - c1 := r.Calls() - c2 := r2.Calls() - max := len(c1) - if len(c2) > len(c1) { - max = len(c2) + /* + r2, err := CallTreeVerifier(env, tree) + if err != nil { + return nil, err } - for i := 0; i < max; i++ { - //zap.S().Error("R1 != R2: failed to call account script on transaction ") - if i <= len(c1)-1 { - zap.S().Error(i, " ", c1[i]) - } else { - zap.S().Error(i, " ", "") + if !r.Eq(r2) { + c1 := r.Calls() + c2 := r2.Calls() + max := len(c1) + if len(c2) > len(c1) { + max = len(c2) } - if i <= len(c2)-1 { - zap.S().Error(i, " ", c2[i]) - } else { - zap.S().Error(i, " ", "") + for i := 0; i < max; i++ { + //zap.S().Error("R1 != R2: failed to call account script on transaction ") + if i <= len(c1)-1 { + zap.S().Error(i, " ", c1[i]) + } else { + zap.S().Error(i, " ", "") + } + if i <= len(c2)-1 { + zap.S().Error(i, " ", c2[i]) + } else { + zap.S().Error(i, " ", "") + } } - } - return nil, errors.New("R1 != R2: failed to call account script on transaction ") - } + return nil, errors.New("R1 != R2: failed to call account script on transaction ") + } + */ return r, nil } @@ -73,20 +74,20 @@ func CallTreeFunction(env RideEnvironment, tree *Tree, name string, args proto.A } func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - rs1, err := CallTreeFunction(env, tree, name, args) - if err != nil { - return nil, errors.Wrap(err, "call function by tree") - } + //rs1, err := CallTreeFunction(env, tree, name, args) + //if err != nil { + // return nil, errors.Wrap(err, "call function by tree") + //} rs2, err := CallFunction2(txID, env, tree, name, args) if err != nil { return rs2, errors.Wrap(err, "call function by vm") } - if !rs1.Eq(rs2) { - zap.S().Errorf("%s, result mismatch", txID) - zap.S().Errorf("tree: %+q", rs1) - zap.S().Errorf("vm : %+q", rs2) - return nil, errors.New(txID + ": result mismatch") - } + //if !rs1.Eq(rs2) { + // zap.S().Errorf("%s, result mismatch", txID) + // zap.S().Errorf("tree: %+q", rs1) + // zap.S().Errorf("vm : %+q", rs2) + // return nil, errors.New(txID + ": result mismatch") + //} return rs2, nil } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index c2d0e83738..83b451604d 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -175,8 +175,9 @@ func (m *vm) run() (rideType, error) { } if point.value != nil { m.push(point.value) - } else if point.fn != nil { - rs, err := point.fn(m.env) + } else if point.fn != 0 { + fn := predefined.getn(int(point.fn)) + rs, err := fn(m.env) if err != nil { return nil, err } From 33f2f24fa7d417fb9bf818c1501797eb7064759d Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 24 Dec 2020 21:00:20 +0300 Subject: [PATCH 29/55] Save entrypoints into meta. --- pkg/ride/compiler2.go | 21 +++ pkg/ride/compiler2_test.go | 285 ++++++++++++++--------------------- pkg/ride/compiler_func.go | 5 +- pkg/ride/compiler_helpers.go | 27 +++- pkg/ride/compiler_main.go | 52 ++++--- pkg/ride/executable.go | 68 ++++++++- pkg/ride/result.go | 11 ++ pkg/ride/vm.go | 8 - 8 files changed, 260 insertions(+), 217 deletions(-) diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 27a5c808a3..0f963bf35b 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -158,6 +158,27 @@ func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments, //return compileFunction(t.LibVersion, t) } +func CompileDapp(txID string, tree *Tree) (*Executable, error) { + if !tree.IsDApp() { + return nil, errors.Errorf("unable to compile dappp") + } + //for i := 0; i < len(tree.Functions); i++ { + // function, ok := tree.Functions[i].(*FunctionDeclarationNode) + // if !ok { + // return nil, 0, errors.New("invalid callable declaration") + // } + // if function.Name == name { + // rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), isDapp) + // if err != nil { + // return rs, 0, err + // } + // return rs, len(function.Arguments), nil + // } + //} + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Functions...), true) + //return nil, 0, errors.Errorf("function '%s' not found", name) +} + /* func compileVerifier(libVersion int, node Node) (*Executable, error) { fCheck, err := selectFunctionChecker(libVersion) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index c872a7504d..527b3ce46f 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -1,13 +1,11 @@ package ride import ( - "bytes" "encoding/base64" "errors" "strconv" "testing" - //"github.com/fxamacker/cbor/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/proto" @@ -52,50 +50,50 @@ func Test22(t *testing.T) { env RideEnvironment res bool }{ - //{`V1: true`, "AQa3b8tH", env, true}, - //{`V1: false`, `AQfeYll6`, nil, false}, - //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, - //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - //{`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, - //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, - //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, - //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - //{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - //{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, - //{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - //{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - //{`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, - //{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - //{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, - //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, - //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, - //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - //{`let x = {let y = true;y}x`, `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C`, nil, true}, - //{`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}, - //{`func abc(addr: Address) = addr == tx.sender;abc(tx.sender)`, "BAoBAAAAA2FiYwAAAAEAAAAEYWRkcgkAAAAAAAACBQAAAARhZGRyCAUAAAACdHgAAAAGc2VuZGVyCQEAAAADYWJjAAAAAQgFAAAAAnR4AAAABnNlbmRlckJrXFI=", env, true}, + {`V1: true`, "AQa3b8tH", env, true}, + {`V1: false`, `AQfeYll6`, nil, false}, + {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, + {`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, + {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, + {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, + {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, + {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, + {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + {`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, + {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, + {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, + {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, + {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + {`let x = {let y = true;y}x`, `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C`, nil, true}, + {`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}, + {`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}, - //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, - //{`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, - //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + {`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, + {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, + {`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, + {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, //{`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}, + {`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, env, true}, } { src, err := base64.StdEncoding.DecodeString(test.source) require.NoError(t, err, test.comment) @@ -117,48 +115,6 @@ func Test22(t *testing.T) { } } -func buildCode(i ...interface{}) ([]byte, uint16) { - marks := make(map[int]uint16) - b := new(bytes.Buffer) - for _, inf := range i { - switch n := inf.(type) { - case byte: - b.WriteByte(n) - case int: - b.WriteByte(byte(n)) - case mark: - marks[n.id] = uint16(b.Len()) - case toMark: - b.Write(encode(marks[n.id])) - } - } - return b.Bytes(), marks[0] -} - -type mark struct { - id int -} - -func at(id int) mark { - return mark{ - id: id, - } -} - -type toMark struct { - id int -} - -func to(id int) toMark { - return toMark{id} -} - -func TestBuildCode(t *testing.T) { - rs, entryPoint := buildCode(1, at(2), 2, at(0), to(2)) - require.Equal(t, []byte{1, 2, 0, 1}, rs) - require.Equal(t, uint16(2), entryPoint) -} - // 1 == 1 func TestCallExternal(t *testing.T) { n := &FunctionCallNode{ @@ -178,6 +134,7 @@ func TestCallExternal(t *testing.T) { require.Equal(t, []byte{ + OpReturn, OpReturn, OpRef, 0, 3, OpRef, 0, 4, @@ -512,43 +469,28 @@ func TestIfStmt(t *testing.T) { /* -let dd = @extrNative(1050)(this,"dd",); -func f(key) { - let $match0 = getBinary(this,key); - if (instanceOf($match0,"ByteVector")) { - let a = $match0; - 2-1 - } else { - 0 - } +{-# 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) + ]) } -let a = ((((f("a",) + f("b",)) + f("c",)) + f("d",)) + f("e",)); -let b = ((((f("g",) + f("h",)) + f("i",)) + f("j",)) + f("k",)); -let c = ((((f("a",) + f("b",)) + f("c",)) + f("d",)) + f("k",)); -let d = ((((f("g",) + f("h",)) + f("i",)) + f("j",)) + f("e",)); -let e = ((((f("a",) + f("b",)) + f("c",)) + f("j",)) + f("e",)); -let g = ((f("g",) + f("h",)) + value(f("i",),)); -if ( - if ( - if ( - if ( - if ( - if ( - if ((dd == 1)) { - (a == 5) - } else { - false - } - ) { (b == parseIntValue("0",)) } else { false }) { (c == 4) } else { false }) { (d == parseIntValue("1",)) } else { false }) { (e == 4) } else { false }) { (g == parseIntValue("0",)) } else { false }) { true } else { 500(tx.bodyBytes,401(tx.proofs,0,),tx.senderPublicKey,) } - - - -AwQAAAACZGQJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAABHRoaXMCAAAAAmRkCgEAAAABZgAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEHAAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAKQnl0ZVZlY3RvcgQAAAABYQUAAAAHJG1hdGNoMAkAAGUAAAACAAAAAAAAAAACAAAAAAAAAAABAAAAAAAAAAAABAAAAAFhCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFlBAAAAAFiCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFrBAAAAAFjCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABZAkBAAAAAWYAAAABAgAAAAFrBAAAAAFkCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABZwkBAAAAAWYAAAABAgAAAAFoCQEAAAABZgAAAAECAAAAAWkJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFlCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAQAAAAFmAAAAAQIAAAABYQkBAAAAAWYAAAABAgAAAAFiCQEAAAABZgAAAAECAAAAAWMJAQAAAAFmAAAAAQIAAAABagkBAAAAAWYAAAABAgAAAAFlBAAAAAFnCQAAZAAAAAIJAABkAAAAAgkBAAAAAWYAAAABAgAAAAFnCQEAAAABZgAAAAECAAAAAWgJAQAAAAV2YWx1ZQAAAAEJAQAAAAFmAAAAAQIAAAABaQMDAwMDAwMJAAAAAAAAAgUAAAACZGQAAAAAAAAAAAEJAAAAAAAAAgUAAAABYQAAAAAAAAAABQcJAAAAAAAAAgUAAAABYgkBAAAADXBhcnNlSW50VmFsdWUAAAABAgAAAAEwBwkAAAAAAAACBQAAAAFjAAAAAAAAAAAEBwkAAAAAAAACBQAAAAFkCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAECAAAAATEHCQAAAAAAAAIFAAAAAWUAAAAAAAAAAAQHCQAAAAAAAAIFAAAAAWcJAQAAAA1wYXJzZUludFZhbHVlAAAAAQIAAAABMAcGCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAgFAAAAAnR4AAAAD3NlbmRlclB1YmxpY0tlebYLD8w= */ -func Test44(t *testing.T) { - source := "AwQAAAALc3RhcnRIZWlnaHQAAAAAAAACvgAEAAAACnN0YXJ0UHJpY2UAAAAAAAX14QAEAAAACGludGVydmFsCQAAaAAAAAIAAAAAAAAAIj4AAAAAAAAAADwEAAAAA2V4cAkAAGgAAAACCQAAaAAAAAIAAAAAAAAAoyAAAAAAAAAAADwAAAAAAAAAA+gEAAAAB1dBVkVTSWQBAAAABBOr2TMEAAAAByRtYXRjaDAFAAAAAnR4AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBAAAAAFlBQAAAAckbWF0Y2gwBAAAAAV5ZWFycwkAAGkAAAACCQAAZQAAAAIFAAAABmhlaWdodAUAAAALc3RhcnRIZWlnaHQFAAAACGludGVydmFsAwMJAABnAAAAAggFAAAAAWUAAAAFcHJpY2UJAABoAAAAAgUAAAAKc3RhcnRQcmljZQkAAGQAAAACAAAAAAAAAAABBQAAAAV5ZWFycwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQgICAUAAAABZQAAAAlzZWxsT3JkZXIAAAAJYXNzZXRQYWlyAAAACnByaWNlQXNzZXQHCQAAZwAAAAIIBQAAAAFlAAAABmFtb3VudAAAAAAABfXhAAcGQlqguw==" +func TestDappMultipleFunctions(t *testing.T) { + source := "AAIDAAAAAAAAAAwIARIDCgEIEgMKAQgAAAAAAAAAAgAAAAFpAQAAAANhYmMAAAABAAAACHF1ZXN0aW9uCQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFhAAAAAAAAAAAFBQAAAANuaWwAAAABaQEAAAADY2JhAAAAAQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQAAAAAAAAAABgUAAAADbmlsAAAAAFEpRso=" src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -557,19 +499,31 @@ func Test44(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - script, err := CompileVerifier("", tree) + script, err := CompileDapp("", tree) require.NoError(t, err) assert.NotNil(t, script) - t.Log(Decompiler(tree.Verifier)) + rs, err := script.Run2(nil, "abc", []rideType{rideString(""), rideString("")}) + require.NoError(t, err) - //res, err := script.Run(env) - //require.NoError(t, err) - //assert.NotNil(t, res) - //r, ok := res.(ScriptResult) - //assert.True(t, ok) - //assert.Equal(t, true, r.Result()) + require.Equal(t, true, rs.Result()) + require.Equal(t, + []proto.ScriptAction{ + &proto.DataEntryScriptAction{ + Entry: &proto.IntegerDataEntry{Value: 5, Key: "a"}, + }, + }, []proto.ScriptAction(rs.ScriptActions())) + rs, err = script.Run2(nil, "cba", []rideType{rideString(""), rideString("")}) + require.NoError(t, err) + + require.Equal(t, true, rs.Result()) + require.Equal(t, + []proto.ScriptAction{ + &proto.DataEntryScriptAction{ + Entry: &proto.IntegerDataEntry{Value: 6, Key: "a"}, + }, + }, []proto.ScriptAction(rs.ScriptActions())) } /* @@ -1031,28 +985,14 @@ func TestCacheInMain(t *testing.T) { transactionFunc: testExchangeWithProofsToObject, } - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 1, - OpRef, 0, 1, - OpExternalCall, 0, 3, 0, 2, - OpClearCache, 0, 1, - OpReturn, - - OpRef, 0, 4, - OpRef, 0, 5, - OpExternalCall, 0, 5, 0, 2, - OpCache, 0, 1, - OpReturn, - OpReturn, - }, - script.ByteCode) - rs, err := script.Run(env, nil) require.NoError(t, err) require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, rs.Result(), true) + + // check that value `x` is cleared before exit + //script. } /* @@ -1199,12 +1139,12 @@ func TestCacheWithIf(t *testing.T) { {-# STDLIB_VERSION 4 #-} {-# CONTENT_TYPE EXPRESSION #-} {-# SCRIPT_TYPE ACCOUNT #-} -func abc(x: String) = true -let y = "7" +func abc(x: Int) = x == x +let y = getIntegerValue(this, "a") abc(y) */ func TestCacheFuncArgs(t *testing.T) { - source := `BAoBAAAAA2FiYwAAAAEAAAABeAYEAAAAAXkCAAAAATcJAQAAAANhYmMAAAABBQAAAAF5eKWK0Q==` + source := `BAoBAAAAA2FiYwAAAAEAAAABeAkAAAAAAAACBQAAAAF4BQAAAAF4BAAAAAF5CQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAAR0aGlzAgAAAAFhCQEAAAADYWJjAAAAAQUAAAABeYsrE7g=` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -1215,46 +1155,38 @@ func TestCacheFuncArgs(t *testing.T) { script, err := CompileVerifier("", tree) require.NoError(t, err) assert.NotNil(t, script) - - env := &MockRideEnvironment{ - transactionFunc: testExchangeWithProofsToObject, + state := &MockSmartState{ + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + return &proto.IntegerDataEntry{ + Value: 1, + }, nil + }, } - - /* */ - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 4, - OpCache, 0, 2, - OpPop, - OpRef, 0, 1, + env := &MockRideEnvironment{ + stateFunc: func() types.SmartState { + return state }, - script.ByteCode[:11]) - /**/ + thisFunc: func() rideType { + return rideAddress{} + }, + } rs, err := script.Run(env, nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) + require.Equal(t, 2, len(rs.Calls())) + // only 1 native call to state + require.Equal(t, "@extrNative(1050)", rs.Calls()[0].name) + // native compare + require.Equal(t, "0", rs.Calls()[1].name) } /* -@i@func sponsorDeposit(compestart,assetName,compenum) { - let compeNum = toString(compenum); - let compeStart = toString(compestart); - let pmt = extract(i.payment); - let paymentId = pmt.assetId; - let currentKey = toBase58String(i.caller.bytes); - let currentAmount = { - let $match0 = 1050(this,currentKey); - if (instanceOf($match0,"Int")) { - let a = $match0; a - } else { - 0 - }; - } - let newAmount = (currentAmount + pmt.amount); - WriteSet(1100(DataEntry((((compeNum + assetName) + compeStart) + currentKey),newAmount),1100(DataEntry((((compeNum + compeStart) + assetName) + currentKey),compestart),nil))) +let x = { + let y = true; + y; } +x */ func TestLetInLet(t *testing.T) { source := `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C` @@ -1266,6 +1198,7 @@ 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) diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 29ff8473d8..a4aebe6846 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -43,6 +43,7 @@ type FuncState struct { // References that defined inside function. deferred []Deferred defers *deferreds + argn int } func (a FuncState) backward(as Fsm) Fsm { @@ -59,7 +60,8 @@ func (a FuncState) Property(name string) Fsm { return propertyTransition(a, a.params, name, a.defers) } -func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { // save reference to global scope, where code lower that function will be able to use it. +func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { + argn := len(args) n := params.u.next() params.r.set(name, n) // all variable we add only visible to current scope, @@ -91,6 +93,7 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP name: "func " + name, }, paramIds: paramIds, + argn: argn, } } diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 36403df9b8..d8da78f25b 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -4,14 +4,23 @@ import "bytes" type constid = uint16 +type Refs map[uint16]point + +type entrypoint struct { + name string + at uint16 + argn uint16 +} + type builder struct { - w *bytes.Buffer - startAt uint16 + w *bytes.Buffer + entrypoints map[string]entrypoint } func newBuilder() *builder { return &builder{ - w: new(bytes.Buffer), + w: new(bytes.Buffer), + entrypoints: make(map[string]entrypoint), } } @@ -28,6 +37,14 @@ func (b *builder) push(uint162 uint16) { b.w.Write(encode(uint162)) } +func (b *builder) setStart(name string, argn int) { + b.entrypoints[name] = entrypoint{ + name: name, + at: b.len(), + argn: uint16(argn), + } +} + func (b *builder) bool(v bool) { if v { b.w.WriteByte(OpTrue) @@ -76,8 +93,8 @@ func (b *builder) call(id uint16, argc uint16) { // b.startAt = uint16(b.w.Len()) //} -func (b *builder) build() (uint16, []byte) { - return 1, b.w.Bytes() +func (b *builder) build() (map[string]entrypoint, []byte) { + return b.entrypoints, b.w.Bytes() } func (b *builder) jpmIfFalse() { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 45837491f2..d098f70d60 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -5,12 +5,12 @@ type MainState struct { params retAssig uint16 - deferred []Deferred + body []Deferred deferreds *deferreds } func (a MainState) backward(state Fsm) Fsm { - a.deferred = append(a.deferred, state.(Deferred)) + a.body = append(a.body, state.(Deferred)) return a } @@ -64,27 +64,35 @@ func (a MainState) Assigment(name string) Fsm { } func (a MainState) Return() Fsm { - reversed := reverse(a.deferred) - - if f, ok := reversed[0].(FuncState); ok && f.invokeParam != "" { - for i := len(f.ParamIds()) - 1; i >= 0; i-- { - a.b.writeByte(OpCache) - a.b.write(encode(f.ParamIds()[i])) - a.b.writeByte(OpPop) - } - } - - for _, v := range reversed[:1] { - v.Write(a.params, nil) - } for _, v := range a.deferreds.Get() { v.deferred.Clean() } a.b.ret() - for _, v := range reversed[1:] { - v.Write(a.params, nil) - a.b.ret() + + //reversed := reverse(a.body) + body := a.body + for { + if f, ok := body[0].(FuncState); ok && f.invokeParam != "" { + a.b.setStart(f.name, f.argn) + for i := len(f.ParamIds()) - 1; i >= 0; i-- { + a.b.writeByte(OpCache) + a.b.write(encode(f.ParamIds()[i])) + a.b.writeByte(OpPop) + } + } + a.b.setStart("", 0) + body[0].Write(a.params, nil) + body = body[1:] + if len(body) == 0 { + break + } } + a.b.ret() + + //for _, v := range reversed[1:] { + // v.Write(a.params, nil) + // a.b.ret() + //} for _, v := range a.deferreds.Get() { pos := a.b.len() @@ -104,22 +112,22 @@ func (a MainState) Call(name string, argc uint16) Fsm { } func (a MainState) Reference(name string) Fsm { - a.deferred = append(a.deferred, reference(a, a.params, name)) + a.body = append(a.body, reference(a, a.params, name)) return a } func (a MainState) Boolean(v bool) Fsm { - a.deferred = append(a.deferred, a.constant(rideBoolean(v))) + a.body = append(a.body, a.constant(rideBoolean(v))) return a } func (a MainState) BuildExecutable(version int, isDapp bool) *Executable { - startAt, code := a.b.build() + entrypoints, code := a.b.build() return &Executable{ LibVersion: version, ByteCode: code, References: a.c.values, - EntryPoints: map[string]uint16{"": startAt}, + EntryPoints: entrypoints, IsDapp: isDapp, } } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 873d9821e0..c0a35a4bc6 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -10,13 +10,13 @@ import ( type Executable struct { LibVersion int ByteCode []byte - EntryPoints map[string]uint16 + EntryPoints map[string]entrypoint References map[uniqueid]point IsDapp bool } func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (RideResult, error) { - vm, err := a.makeVm(environment, arguments) + vm, err := a.makeVm(environment, int(a.EntryPoints[""].at), arguments) if err != nil { return nil, err } @@ -25,6 +25,63 @@ func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (Rid return nil, err } switch tv := v.(type) { + case rideThrow: + if a.IsDapp { + return DAppResult{res: false, msg: string(tv), calls: vm.calls, refs: vm.ref}, nil + } + return ScriptResult{res: false, msg: string(tv), calls: vm.calls, refs: vm.ref}, nil + case rideBoolean: + return ScriptResult{res: bool(tv), operations: vm.numOperations, calls: vm.calls, refs: vm.ref}, nil + case rideObject: + actions, err := objectToActions(vm.env, tv) + if err != nil { + return nil, errors.Wrap(err, "failed to convert evaluation result") + } + return DAppResult{res: true, actions: actions, msg: "", calls: vm.calls, refs: vm.ref}, nil + case rideList: + actions := make([]proto.ScriptAction, len(tv)) + for i, item := range tv { + a, err := convertToAction(vm.env, item) + if err != nil { + return nil, errors.Wrap(err, "failed to convert evaluation result") + } + actions[i] = a + } + return DAppResult{res: true, actions: actions, calls: vm.calls, refs: vm.ref}, nil + default: + return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) + } +} + +func (a *Executable) Run2(environment RideEnvironment, name string, arguments []rideType) (RideResult, error) { + fcall, ok := a.EntryPoints[name] + if !ok { + return nil, errors.Errorf("function %s not found", name) + } + if len(arguments) != int(fcall.argn)+1 { + return nil, errors.Errorf("func `%s` requires %d arguments(1 invoke + %d args), but provided %d", name, fcall.argn+1, fcall.argn, len(arguments)) + } + vm, err := a.makeVm(environment, int(fcall.at), arguments) + if err != nil { + return nil, err + } + //vm := &vm{ + // code: a.ByteCode, + // ip: int(fcall.at), + // functions: fSelect, + // functionName: provider, + // env: environment, + // ref: a.References, + // stack: arguments, + //} + //if err != nil { + // return nil, err + //} + v, err := vm.run() + if err != nil { + return nil, err + } + switch tv := v.(type) { case rideThrow: if a.IsDapp { return DAppResult{res: false, msg: string(tv), calls: vm.calls}, nil @@ -54,14 +111,14 @@ func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (Rid } func (a *Executable) run(environment RideEnvironment, arguments []rideType) (rideType, error) { - vm, err := a.makeVm(environment, arguments) + vm, err := a.makeVm(environment, int(a.EntryPoints[""].at), arguments) if err != nil { return nil, err } return vm.run() } -func (a *Executable) makeVm(environment RideEnvironment, arguments []rideType) (*vm, error) { +func (a *Executable) makeVm(environment RideEnvironment, entrypoint int, arguments []rideType) (*vm, error) { fSelect, err := selectFunctions(a.LibVersion) if err != nil { return nil, err @@ -72,12 +129,13 @@ func (a *Executable) makeVm(environment RideEnvironment, arguments []rideType) ( } return &vm{ code: a.ByteCode, - ip: int(a.EntryPoints[""]), + ip: int(a.EntryPoints[""].at), functions: fSelect, functionName: provider, env: environment, ref: a.References, stack: arguments, + jmps: []int{1}, }, nil } diff --git a/pkg/ride/result.go b/pkg/ride/result.go index 8547a27d02..5f2a507e80 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -11,6 +11,7 @@ type RideResult interface { ScriptActions() proto.ScriptActions Eq(RideResult) bool Calls() []callLog + Refs() Refs } type ScriptResult struct { @@ -18,12 +19,17 @@ type ScriptResult struct { msg string operations int calls []callLog + refs Refs } func (r ScriptResult) Result() bool { return r.res } +func (r ScriptResult) Refs() Refs { + return r.refs +} + func (r ScriptResult) Calls() []callLog { return r.calls } @@ -51,12 +57,17 @@ type DAppResult struct { msg string operations int calls []callLog + refs Refs } func (r DAppResult) Result() bool { return r.res } +func (r DAppResult) Refs() Refs { + return r.refs +} + func (r DAppResult) Calls() []callLog { return r.calls } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 83b451604d..d7997d3a54 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -14,14 +14,11 @@ type vm struct { env RideEnvironment code []byte ip int - constants []rideType functions func(int) rideFunction - globals func(int) rideConstructor stack []rideType functionName func(int) string jmps []int ref map[uint16]point - cache bool calls []callLog numOperations int } @@ -225,8 +222,3 @@ func (m *vm) uint16() uint16 { m.ip += 2 return res } - -func (m *vm) constant() rideType { - //TODO: add check - return m.constants[m.arg16()] -} From 36be49d3592c94ff8a0bf6679811aa6c74f0c576 Mon Sep 17 00:00:00 2001 From: Frozen Date: Sun, 24 Jan 2021 13:34:21 +0300 Subject: [PATCH 30/55] Testnet random script. --- pkg/proto/proto_test.go | 11 + pkg/ride/compiler2.go | 179 ++++---- pkg/ride/compiler2_test.go | 613 ++++++++++++++++----------- pkg/ride/compiler_func.go | 5 - pkg/ride/compiler_helpers.go | 134 ++++-- pkg/ride/compiler_main.go | 15 +- pkg/ride/constants.go | 128 +++--- pkg/ride/decompiler.go | 30 ++ pkg/ride/deserializer.go | 132 ++++++ pkg/ride/deserializer_test.go | 56 +++ pkg/ride/executable.go | 220 +++++++--- pkg/ride/executable_test.go | 30 ++ pkg/ride/functions_predefined.go | 51 +-- pkg/ride/generate/main.go | 8 + pkg/ride/opcodes.go | 2 +- pkg/ride/reverse_tree.go | 638 +++++++++++++++++++++++++++-- pkg/ride/reverse_tree_test.go | 573 ++++++++++++++++++++++++-- pkg/ride/reversed_tree.go | 162 ++++++-- pkg/ride/runtime.go | 53 +++ pkg/ride/serializer.go | 127 +++++- pkg/ride/tree.go | 4 + pkg/ride/tree_evaluation.go | 70 ++-- pkg/ride/tree_evaluation_test.go | 14 +- pkg/ride/tuples.go | 84 ++++ pkg/ride/vm.go | 32 +- pkg/state/invoke_applier.go | 15 +- pkg/state/script_caller.go | 33 +- pkg/state/scripts_cache.go | 12 +- pkg/state/scripts_storage.go | 186 +++++++-- pkg/state/scripts_storage_test.go | 32 +- pkg/state/transaction_checker.go | 2 +- pkg/state/transaction_performer.go | 14 +- 32 files changed, 2885 insertions(+), 780 deletions(-) create mode 100644 pkg/ride/deserializer.go create mode 100644 pkg/ride/deserializer_test.go create mode 100644 pkg/ride/executable_test.go diff --git a/pkg/proto/proto_test.go b/pkg/proto/proto_test.go index 84e1ac050b..b66386cd20 100644 --- a/pkg/proto/proto_test.go +++ b/pkg/proto/proto_test.go @@ -558,6 +558,7 @@ func TestGetBlockMessage_MarshalBinary(t *testing.T) { } rs, err := b.MarshalBinary() + t.Log(rs) require.NoError(t, err) b2 := GetBlockMessage{} @@ -616,3 +617,13 @@ func TestTCPAddr_ToUint64(t *testing.T) { require.True(t, a.Equal(b)) } + +func TestGetPeersMessage_MarshalBinary(t *testing.T) { + m := GetPeersMessage{} + bts, err := m.MarshalBinary() + require.NoError(t, err) + t.Log(bts) + + err = m.UnmarshalBinary(bts) + require.NoError(t, err) +} diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 0f963bf35b..8f20952fb3 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -1,8 +1,9 @@ package ride import ( + "math" + "github.com/pkg/errors" - "github.com/wavesplatform/gowaves/pkg/proto" "go.uber.org/zap" ) @@ -69,116 +70,95 @@ func ccc(f Fsm, node Node) (Fsm, error) { } func CompileVerifier(txID string, tree *Tree) (*Executable, error) { - //s, err := newEvaluationScope(tree.LibVersion, env) - //if err != nil { - // return nil, errors.Wrap(err, "failed to create scope") - //} if tree.IsDApp() { if tree.HasVerifier() { _, ok := tree.Verifier.(*FunctionDeclarationNode) if !ok { return nil, errors.New("invalid verifier declaration") } - //for _, declaration := range tree.Declarations { - // err = s.declare(declaration) - // if err != nil { - // return nil, errors.Wrap(err, "invalid declaration") - // } - //} - return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier), tree.IsDApp()) - //s.constants[verifier.invocationParameter] = esConstant{c: newTx} - //return &treeEvaluator{ - // dapp: tree.IsDApp(), - // f: verifier.Body, // In DApp verifier is a function, so we have to pass its body - // s: s, - // env: env, - //}, nil + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier), tree.IsDApp(), tree.HasVerifier()) } return nil, errors.New("no verifier declaration") } - return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, tree.IsDApp()) -} - -type namedArgument struct { - name string - arg rideType + return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, tree.IsDApp(), tree.HasVerifier()) } type functionArgumentsCount = int -func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments, isDapp bool) (*Executable, functionArgumentsCount, error) { - //s, err := newEvaluationScope(tree.LibVersion, env) - //if err != nil { - // return nil, errors.Wrap(err, "failed to create scope") - //} - //for i, declaration := range tree.Declarations { - // //err = s.declare(declaration) - // //if err != nil { - // // return nil, errors.Wrap(err, "invalid declaration") - // //} - // zap.S().Errorf("decl #%d ?? %s", i, Decompiler(declaration)) - //} - if !tree.IsDApp() { - return nil, 0, errors.Errorf("unable to call function '%s' on simple script", name) - } - for i := 0; i < len(tree.Functions); i++ { - function, ok := tree.Functions[i].(*FunctionDeclarationNode) - if !ok { - return nil, 0, errors.New("invalid callable declaration") - } - if function.Name == name { - //s.constants[function.invocationParameter] = esConstant{c: newInvocation} - //if l := len(args); l != len(function.Arguments) { - // return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) - //} - //applyArgs := make([]rideType, 0, len(args)) - //for _, arg := range args { - // a, err := convertArgument(arg) - // if err != nil { - // return nil, errors.Wrapf(err, "failed to call function '%s'", name) - // } - // //s.pushValue(function.Arguments[i], a) - // applyArgs = append(applyArgs, a) - // //namedArgument{ - // // name: function.Arguments[i], - // // arg: a, - // //}) - //} - - rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), isDapp) - if err != nil { - return rs, 0, err - } - return rs, len(function.Arguments), nil - //return &treeEvaluator{dapp: true, f: function.Body, s: s, env: env}, nil - } - } - return nil, 0, errors.Errorf("function '%s' not found", name) - - //return compileFunction(t.LibVersion, t) -} +//func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments, isDapp bool) (*Executable, functionArgumentsCount, error) { +// //s, err := newEvaluationScope(tree.LibVersion, env) +// //if err != nil { +// // return nil, errors.Wrap(err, "failed to create scope") +// //} +// //for i, declaration := range tree.Declarations { +// // //err = s.declare(declaration) +// // //if err != nil { +// // // return nil, errors.Wrap(err, "invalid declaration") +// // //} +// // zap.S().Errorf("decl #%d ?? %s", i, Decompiler(declaration)) +// //} +// if !tree.IsDApp() { +// return nil, 0, errors.Errorf("unable to call function '%s' on simple script", name) +// } +// for i := 0; i < len(tree.Functions); i++ { +// function, ok := tree.Functions[i].(*FunctionDeclarationNode) +// if !ok { +// return nil, 0, errors.New("invalid callable declaration") +// } +// if function.Name == name { +// //s.constants[function.invocationParameter] = esConstant{c: newInvocation} +// //if l := len(args); l != len(function.Arguments) { +// // return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) +// //} +// //applyArgs := make([]rideType, 0, len(args)) +// //for _, arg := range args { +// // a, err := convertArgument(arg) +// // if err != nil { +// // return nil, errors.Wrapf(err, "failed to call function '%s'", name) +// // } +// // //s.pushValue(function.Arguments[i], a) +// // applyArgs = append(applyArgs, a) +// // //namedArgument{ +// // // name: function.Arguments[i], +// // // arg: a, +// // //}) +// //} +// +// rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), isDapp, tree.HasVerifier()) +// if err != nil { +// return rs, 0, err +// } +// return rs, len(function.Arguments), nil +// //return &treeEvaluator{dapp: true, f: function.Body, s: s, env: env}, nil +// } +// } +// return nil, 0, errors.Errorf("function '%s' not found", name) +// +// //return compileFunction(t.LibVersion, t) +//} func CompileDapp(txID string, tree *Tree) (*Executable, error) { if !tree.IsDApp() { return nil, errors.Errorf("unable to compile dappp") } - //for i := 0; i < len(tree.Functions); i++ { - // function, ok := tree.Functions[i].(*FunctionDeclarationNode) - // if !ok { - // return nil, 0, errors.New("invalid callable declaration") - // } - // if function.Name == name { - // rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), isDapp) - // if err != nil { - // return rs, 0, err - // } - // return rs, len(function.Arguments), nil - // } - //} - return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Functions...), true) - //return nil, 0, errors.Errorf("function '%s' not found", name) + fns := tree.Functions + if tree.HasVerifier() { + fns = append(fns, tree.Verifier) + } + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, fns...), true, tree.HasVerifier()) } +//func CompileFlatDapp(txID string, tree *Tree) (*Executable, error) { +// if !tree.IsDApp() { +// return nil, errors.Errorf("unable to compile dappp") +// } +// fns := tree.Functions +// if tree.HasVerifier() { +// fns = append(fns, tree.Verifier) +// } +// return compileFunction(txID, tree.LibVersion, append(tree.Declarations, fns...), true, tree.HasVerifier()) +//} + /* func compileVerifier(libVersion int, node Node) (*Executable, error) { fCheck, err := selectFunctionChecker(libVersion) @@ -214,7 +194,7 @@ func compileVerifier(libVersion int, node Node) (*Executable, error) { } */ -func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool) (*Executable, error) { +func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool, hasVerifier bool) (*Executable, error) { fCheck, err := selectFunctionChecker(libVersion) if err != nil { return nil, err @@ -234,7 +214,7 @@ func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool) (*E txID: txID, } for k, v := range predefinedFunctions { - params.addPredefined(k, v.id, v.id) + params.addPredefined(v.name, uint16(math.MaxUint16-k), uint16(math.MaxUint16-k)) } f := NewMain(params) @@ -248,5 +228,16 @@ func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool) (*E // Just to write `OpReturn` to bytecode. f = f.Return() - return f.(BuildExecutable).BuildExecutable(libVersion, isDapp), nil + return f.(BuildExecutable).BuildExecutable(libVersion, isDapp, hasVerifier), nil } + +func CompileTree(tx string, tree *Tree) (*Executable, error) { + if tree.IsDApp() { + return CompileDapp(tx, tree) + } + return CompileVerifier(tx, tree) +} + +//func CompileTree(tx string, tree *Tree) (*Executable, error) { +// return CompileFlatTree(tree) +//} diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 527b3ce46f..18d90d7ece 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -91,8 +91,8 @@ func Test22(t *testing.T) { {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, - //{`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}, + {`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}, } { src, err := base64.StdEncoding.DecodeString(test.source) @@ -102,11 +102,11 @@ func Test22(t *testing.T) { require.NoError(t, err, test.comment) assert.NotNil(t, tree, test.comment) - script, err := CompileVerifier("", tree) + script, err := CompileTree("", tree) require.NoError(t, err, test.comment) assert.NotNil(t, script, test.comment) - res, err := script.Run(test.env, nil) + res, err := script.Verify(test.env) require.NoError(t, err, test.comment) assert.NotNil(t, res, test.comment) r, ok := res.(ScriptResult) @@ -129,7 +129,7 @@ func TestCallExternal(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}, false) + f, err := compileFunction("", 3, []Node{n}, false, true) require.NoError(t, err) require.Equal(t, @@ -158,7 +158,7 @@ func TestIfConditionRightByteCode(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}, false) + f, err := compileFunction("", 3, []Node{n}, false, true) require.NoError(t, err) /** @@ -180,7 +180,7 @@ func TestIfConditionRightByteCode(t *testing.T) { /**/ - rs, err := f.Run(nil, nil) + rs, err := f.Verify(nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } @@ -199,32 +199,7 @@ func TestCall(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - //f, err := compileFunction("", 3, []Node{n}) - //require.NoError(t, err) - - //require.Equal(t, - // []byte{ - // OpReturn, - // OpRef, 0, 3, - // OpRef, 0, 4, - // OpExternalCall, 0, 3, 0, 2, - // OpReturn, - // - // OpRef, 0, 5, - // OpExternalCall, 0, 0x8c, 0, 1, - // OpReturn, - // - // //OpRef, 0, 3, - // //OpReturn, - // //OpRef, 0, 4, - // //OpReturn, - // //OpReturn, - // }, - // script.ByteCode) - - rs, err := script.Run(nil, nil) - require.NoError(t, err) - //rs, err := f.Run(nil, nil) + rs, err := script.Verify(nil) require.NoError(t, err) require.Equal(t, 2, len(rs.Calls())) require.Equal(t, false, rs.Result()) @@ -252,73 +227,14 @@ func TestDoubleCall(t *testing.T) { }, } - f, err := compileFunction("", 3, []Node{n}, false) + f, err := compileFunction("", 3, []Node{n}, false, true) require.NoError(t, err) - /** - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 1, - OpRef, 0, 2, - OpExternalCall, 0, 3, 0, 2, - OpReturn, - - OpRef, 0, 3, - OpReturn, - }, - f.ByteCode) - /**/ - - require.EqualValues(t, 1, f.EntryPoints[""]) - - rs, err := f.Run(nil, nil) + rs, err := f.Verify(nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } -/* -func abc() { - let x = 5 - let y = 6 - x -} -*/ -func TestClearInternalVariables(t *testing.T) { - n := &FunctionDeclarationNode{ - Name: "abc", - Arguments: nil, - Body: &AssignmentNode{ - Name: "x", - Expression: &LongNode{Value: 5}, - Block: &AssignmentNode{ - Name: "y", - Expression: &LongNode{Value: 6}, - Block: &ReferenceNode{ - Name: "x", - }, - }, - }, - } - - f, err := compileFunction("", 3, []Node{n}, false) - require.NoError(t, err) - - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 2, - OpClearCache, 0, 2, - OpClearCache, 0, 4, - OpReturn, - OpRef, 0, 3, OpCache, 0, 2, OpReturn, OpReturn, - OpRef, 0, 5, OpCache, 0, 4, OpReturn, OpReturn, - - OpReturn, - }, - f.ByteCode) -} - // func id(v: Boolean) = v; id(true) func TestCallWithConstArg(t *testing.T) { n := &FunctionDeclarationNode{ @@ -336,31 +252,10 @@ func TestCallWithConstArg(t *testing.T) { invocationParameter: "", } - f, err := compileFunction("", 3, []Node{n}, false) + f, err := compileFunction("", 3, []Node{n}, false, true) require.NoError(t, err) - bt := []byte{ - OpReturn, - OpRef, 0, 3, - OpCache, 0, 2, // Function execution code. One line: reference to `v` argument. - OpPop, - OpRef, 0, 1, - OpReturn, - OpReturn, - - // call function - OpRef, 0, 2, - OpReturn, - OpReturn, - } - - //require.Equal(t, 1, 1, bt) - require.Equal(t, bt, f.ByteCode) - - //f.ByteCode = bt - //f.EntryPoints[""] = 4 - - rs, err := f.Run(nil, nil) + rs, err := f.Verify(nil) require.NoError(t, err) require.Equal(t, true, rs.Result()) } @@ -396,7 +291,7 @@ func TestMultipleCallConstantFuncArgument(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - res, err := script.Run(env, nil) + res, err := script.Verify(env) require.NoError(t, err) assert.NotNil(t, res) r, ok := res.(ScriptResult) @@ -451,13 +346,13 @@ func TestIfStmt(t *testing.T) { script, err := CompileVerifier("", tree) require.NoError(t, err) - assert.NotNil(t, script) + require.NotNil(t, script) - res, err := script.Run(env, nil) + res, err := script.Verify(env) require.NoError(t, err) - assert.NotNil(t, res) + require.NotNil(t, res) r, ok := res.(ScriptResult) - assert.True(t, ok) + require.True(t, ok) for _, l := range r.calls { t.Log(l) @@ -486,9 +381,7 @@ func cba(question: String) = { DataEntry("a", 6) ]) } - */ - func TestDappMultipleFunctions(t *testing.T) { source := "AAIDAAAAAAAAAAwIARIDCgEIEgMKAQgAAAAAAAAAAgAAAAFpAQAAAANhYmMAAAABAAAACHF1ZXN0aW9uCQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFhAAAAAAAAAAAFBQAAAANuaWwAAAABaQEAAAADY2JhAAAAAQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQAAAAAAAAAABgUAAAADbmlsAAAAAFEpRso=" @@ -503,7 +396,7 @@ func TestDappMultipleFunctions(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - rs, err := script.Run2(nil, "abc", []rideType{rideString(""), rideString("")}) + rs, err := script.Invoke(nil, "abc", []rideType{rideString(""), rideString("")}) require.NoError(t, err) require.Equal(t, true, rs.Result()) @@ -514,7 +407,7 @@ func TestDappMultipleFunctions(t *testing.T) { }, }, []proto.ScriptAction(rs.ScriptActions())) - rs, err = script.Run2(nil, "cba", []rideType{rideString(""), rideString("")}) + rs, err = script.Invoke(nil, "cba", []rideType{rideString(""), rideString("")}) require.NoError(t, err) require.Equal(t, true, rs.Result()) @@ -605,7 +498,7 @@ func Test777(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - res, err := script.Run(env, nil) + res, err := script.Verify(env) require.NoError(t, err) assert.NotNil(t, res) r, ok := res.(ScriptResult) @@ -684,7 +577,7 @@ func Test888(t *testing.T) { script.ByteCode) /**/ - rs, err := script.Run(env, nil) + rs, err := script.Verify(env) require.Equal(t, rs.Result(), false) //require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"") } @@ -781,7 +674,7 @@ func TestNoDuplicateCallToState(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - rs, err := script.Run(env, []rideType{env.transaction()}) + rs, err := script.Verify(env) require.NoError(t, err) for _, c := range rs.Calls() { t.Log(c) @@ -848,7 +741,7 @@ func TestDappVerifyVm(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - rs, err := script.Run(nil, []rideType{testTransferObject()}) + rs, err := script.Verify(nil) require.NoError(t, err) require.Equal(t, rs.Result(), true) } @@ -880,7 +773,7 @@ func TestMultipleProperty(t *testing.T) { transactionFunc: testExchangeWithProofsToObject, } - rs, err := script.Run(env, nil) + rs, err := script.Verify(env) require.NoError(t, err) require.Equal(t, rs.Result(), true) } @@ -907,6 +800,7 @@ func TestProperty(t *testing.T) { require.Equal(t, []byte{ + OpReturn, OpReturn, OpRef, 255, 255, OpRef, 0, 2, @@ -941,6 +835,7 @@ func TestProperty(t *testing.T) { require.Equal(t, []byte{ + OpReturn, OpReturn, OpRef, 0, 3, OpRef, 0, 4, @@ -985,14 +880,10 @@ func TestCacheInMain(t *testing.T) { transactionFunc: testExchangeWithProofsToObject, } - rs, err := script.Run(env, nil) + rs, err := script.Verify(env) require.NoError(t, err) require.Equal(t, 2, len(rs.Calls())) - require.Equal(t, rs.Result(), true) - - // check that value `x` is cleared before exit - //script. } /* @@ -1023,118 +914,12 @@ func TestCacheInFunc(t *testing.T) { transactionFunc: testExchangeWithProofsToObject, } - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 1, - OpReturn, - OpReturn, - - OpRef, 0, 2, - OpRef, 0, 2, - OpExternalCall, 0, 3, 0, 2, - OpClearCache, 0, 2, - OpReturn, - OpRef, 0, 5, - OpRef, 0, 6, - OpExternalCall, 0, 5, 0, 2, - OpCache, 0, 2, - OpReturn, - - OpReturn, - OpReturn, - }, - script.ByteCode) - - rs, err := script.Run(env, nil) + rs, err := script.Verify(env) require.NoError(t, err) require.Equal(t, 2, len(rs.Calls())) require.Equal(t, rs.Result(), true) } -/* -func getInt(key: String) = { - match getInteger(this, key) { - case x : Int => x - case _ => 0 - } -} -*/ -func TestCacheWithIf(t *testing.T) { - t.Skip() - n := &FunctionDeclarationNode{ - Name: "abc", - Arguments: []string{"key"}, - Body: &AssignmentNode{ - Name: "$match0", - Expression: &FunctionCallNode{ - Name: "1050", - Arguments: []Node{ - &ReferenceNode{Name: "this"}, - &ReferenceNode{Name: "key"}, - }, - }, - Block: &ConditionalNode{ - Condition: &FunctionCallNode{ - Name: "1", - Arguments: []Node{ - &ReferenceNode{Name: "$match0"}, - &StringNode{Value: "Int"}, - }, - }, - TrueExpression: &AssignmentNode{ - Name: "a", - Expression: &ReferenceNode{Name: "$match0"}, - Block: &ReferenceNode{Name: "a"}, - }, - FalseExpression: &LongNode{Value: 0}, - }, - }, - } - - tree := &Tree{ - LibVersion: 3, - AppVersion: scriptApplicationVersion, - Verifier: n, - } - - script, err := CompileVerifier("", tree) - require.NoError(t, err) - assert.NotNil(t, script) - - env := &MockRideEnvironment{ - transactionFunc: testExchangeWithProofsToObject, - thisFunc: func() rideType { - return rideAddress{} - }, - } - - /* - require.Equal(t, - []byte{ - OpReturn, - OpRef, 0, 11, - OpJumpIfFalse, 0x0, 11, 0x0, 15, 0x0, 19, - OpRef, 0x0, 0x9, 0x1, // true 11 - OpRef, 0x0, 0xa, 0x1, // false 15 - - // next 19 - - OpClearCache, 0, 11, - OpClearCache, 0, 11, - OpReturn, - //OpRef, 0, 5, - //OpProperty, - //OpReturn, - //OpReturn, - }, - script.ByteCode) - */ - - _, err = script.run(env, nil) - require.NoError(t, err) -} - /* {-# STDLIB_VERSION 4 #-} {-# CONTENT_TYPE EXPRESSION #-} @@ -1171,7 +956,7 @@ func TestCacheFuncArgs(t *testing.T) { }, } - rs, err := script.Run(env, nil) + rs, err := script.Verify(env) require.NoError(t, err) require.Equal(t, true, rs.Result()) require.Equal(t, 2, len(rs.Calls())) @@ -1220,7 +1005,345 @@ func TestLetInLet(t *testing.T) { script.ByteCode[:11]) /**/ - rs, err := script.Run(env, nil) + 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) { + source := `AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileTree("", tree) + require.NoError(t, err) + require.NotNil(t, script) + require.Equal(t, 4, len(script.EntryPoints)) +} + +/* + + + */ + +func TestRandomScript(t *testing.T) { + source := `AAIDAAAAAAAAAAgIARIECgIIAgAAAAYAAAAACVJTQVBVQkxJQwkAAlsAAAABAgAAAY9iYXNlNjQ6TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFxbEFpQU5TbUJwREhZS1A5c0tnZU4vbDFiQWIyOGcvdEdsZ0Rrd1Q1RmlNTjRYM3B3ZHZkeEU3bXZTUjgvNDFkVTlyeDRqRys2dFpwYjFVTFZEUHM0MzF0UjJJUmFUWHc1Q2orQWMydmhMKzVKYW1DZXJHRDFVVytiaC9FR1F0eG84VzNZTERyb2ZYQjVRSEp4NFBrejJLZ2Yrb1MvQzhoSHVCL1U0a3JPNzZVMDUwN0dUalpQUDlrUlEwdUxTTWVxUVh0OHdYUytuTXA1d2FqcXhQcERMTWFTUkVnc0t3di9BRWtQNGR6cFRZYmlrTEJZbDRxdGRKc0Q4NEhMRlNraXdkM0JoY09yUGpvSVltTHhRdUJENVRJTUtUS0Qzc2RaZ2FZOXJzeXF4M0EwMGlubnl4RDZ6cDNiNGdGcFVPWDhKeEtaZEVDMm15RXFsZU5nZzdHendJREFRQUIAAAAABlNFUlZFUgkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzTkNpRzI4TG1XeVRpZ1dHMTNFNVFudmRIQnNaRllYU1MyagEAAAAJUmFuZFRvU3RyAAAAAQAAAAFyAwMJAABnAAAAAgUAAAABcgAAAAAAAAAAAQkAAGcAAAACAAAAAAAAAABkBQAAAAFyBwkAAaQAAAABBQAAAAFyCQAAAgAAAAEJAAEsAAAAAgIAAAA8VW5zdXBwb3J0ZWQgciBwYXJhbWV0ZXIgcGFzc2VkOiBleHBlY3RlZD1bMSwuLi4sMTAwXSBhY3R1YWw9CQABpAAAAAEFAAAAAXIBAAAAA2FicwAAAAEAAAADdmFsAwkAAGYAAAACAAAAAAAAAAAABQAAAAN2YWwJAQAAAAEtAAAAAQUAAAADdmFsBQAAAAN2YWwBAAAACE5leHRSYW5kAAAAAgAAAA1jdXJyUmFuZHNWZWN0AAAADXJlbWFpbmluZ0hhc2gEAAAAC25leHRSYW5kSW50CQEAAAADYWJzAAAAAQkABLEAAAABBQAAAA1yZW1haW5pbmdIYXNoBAAAAAxuZXh0UmFuZFZlY3QJAAGaAAAAAQUAAAALbmV4dFJhbmRJbnQEAAAAAXMJAABpAAAAAgkAAMgAAAABBQAAAA1jdXJyUmFuZHNWZWN0AAAAAAAAAAAICQAETAAAAAIFAAAADG5leHRSYW5kVmVjdAkABEwAAAACCQAAygAAAAIFAAAADXJlbWFpbmluZ0hhc2gAAAAAAAAAAAEFAAAAA25pbAEAAAASR2VuZXJhdGVSYW5kVmVjdG9yAAAAAwAAAAlzZXNzaW9uSWQAAAABcwAAAAdyc2FTaWduBAAAAAhlbXB0eVZlYwkAAZsAAAABAgAAAAAEAAAAC3JzYVNpZ1ZhbGlkCQAB+AAAAAQFAAAABlNIQTI1NgkAAZsAAAABBQAAAAlzZXNzaW9uSWQFAAAAB3JzYVNpZ24FAAAACVJTQVBVQkxJQwMFAAAAC3JzYVNpZ1ZhbGlkBAAAAAhyYW5kSGFzaAkAAfcAAAABBQAAAAdyc2FTaWduBAAAAAluZXh0SW5mbzEJAQAAAAhOZXh0UmFuZAAAAAIFAAAACGVtcHR5VmVjBQAAAAhyYW5kSGFzaAkAAZEAAAACCQEAAAAITmV4dFJhbmQAAAACCQABkQAAAAIFAAAACW5leHRJbmZvMQAAAAAAAAAAAAkAAZEAAAACBQAAAAluZXh0SW5mbzEAAAAAAAAAAAEAAAAAAAAAAAAJAAACAAAAAQIAAAAVSW52YWxpZCBSU0Egc2lnbmF0dXJlAAAAAQAAAAFpAQAAAAZyYW5kb20AAAACAAAACXNlc3Npb25JZAAAAAdyc2FTaWduBAAAAAhjdXJyVmVjdAkBAAAAEkdlbmVyYXRlUmFuZFZlY3RvcgAAAAMFAAAACXNlc3Npb25JZAAAAAAAAAAACgUAAAAHcnNhU2lnbgQAAAABcwkAAMgAAAABBQAAAAhjdXJyVmVjdAQAAAAFcmFuZDEDCQAAZwAAAAIFAAAAAXMAAAAAAAAAAAEJAAGkAAAAAQkABLEAAAABCQAAyQAAAAIJAADKAAAAAgUAAAAIY3VyclZlY3QAAAAAAAAAAAAAAAAAAAAAAAgCAAAAAAQAAAAFcmFuZDIDCQAAZwAAAAIFAAAAAXMAAAAAAAAAAAIJAAEsAAAAAgkAASwAAAACBQAAAAVyYW5kMQIAAAABXwkAAaQAAAABCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAAhjdXJyVmVjdAkAAGgAAAACAAAAAAAAAAABAAAAAAAAAAAIAAAAAAAAAAAIBQAAAAVyYW5kMQkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAARR2VuZXJhdGVkX051bWJlcnMFAAAABXJhbmQyBQAAAANuaWwAAAAAKwqyHg==` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileTree("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + //ser := NewSerializer() + //err = script.Serialize(ser) + //require.NoError(t, err) + + //deser := NewDeserializer() + //script, err = DeserializeExecutable(ser.Source()) + //require.NoError(t, err) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + + //random("123123123", "base64:RBuQVdRoLd+fCs0ZZLeHH1WG+oV2a8bLIl4TJow4Qkyqsp/5+4V0LlC+kiPRQuurcackzAgQFZPzV1wNvcVDO+wlFg+gzguL4D382XFClWZ6w+fE/WUrb5Bt893k0Bz7UeEsCu9pDfy41eC1gWDGt0qvKFu+la5MPx/dq10bjVu+2JlBWF2ZBMPD0rrpe+2ZE/JVcaNv+Hf6PS16eHhhiA5Ydsoynsv7vIdZw6atux7J/0VhxxOAUj+LKt92ayBakS5sUnfeOVG1P5Dc9DI1A6MxEK/Xs1ii6NaSaQgU+hWD+472tq47iG4E493wBKHSVV6GP45VLxn23CBBjogeOQ==") + + bts, err := base64.StdEncoding.DecodeString("RBuQVdRoLd+fCs0ZZLeHH1WG+oV2a8bLIl4TJow4Qkyqsp/5+4V0LlC+kiPRQuurcackzAgQFZPzV1wNvcVDO+wlFg+gzguL4D382XFClWZ6w+fE/WUrb5Bt893k0Bz7UeEsCu9pDfy41eC1gWDGt0qvKFu+la5MPx/dq10bjVu+2JlBWF2ZBMPD0rrpe+2ZE/JVcaNv+Hf6PS16eHhhiA5Ydsoynsv7vIdZw6atux7J/0VhxxOAUj+LKt92ayBakS5sUnfeOVG1P5Dc9DI1A6MxEK/Xs1ii6NaSaQgU+hWD+472tq47iG4E493wBKHSVV6GP45VLxn23CBBjogeOQ==") + require.NoError(t, err) + + arguments := proto.Arguments{} + arguments.Append(&proto.StringArgument{Value: "123123123"}) + arguments.Append(&proto.BinaryArgument{Value: bts}) + + rs, err := CallTreeFunction(env, tree, "random", arguments) + //rs, err := script.Invoke(env, "random", []rideType{rideUnit{}, rideString("123123123"), rideBytes(bts)}) + //for i, c := range rs.Calls() { + // t.Log(i, c) + //} + require.NoError(t, err) + require.Equal(t, rs.Result(), true) +} + +func BenchmarkVm(b *testing.B) { + source := "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=" + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(b, err) + + tree, err := Parse(src) + require.NoError(b, err) + + script, err := CompileTree("", tree) + require.NoError(b, err) + + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + } + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + stateFunc: func() types.SmartState { + return state + }, + thisFunc: func() rideType { + return rideAddress{} + }, + } + + b.ReportAllocs() + b.StopTimer() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StartTimer() + rs, err := script.Verify(env) + require.Equal(b, 5, len(rs.Calls())) + b.StopTimer() + require.NoError(b, err) + } +} + +func BenchmarkTree(b *testing.B) { + source := "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=" + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(b, err) + + tree, err := Parse(src) + require.NoError(b, err) + + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + } + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + stateFunc: func() types.SmartState { + return state + }, + thisFunc: func() rideType { + return rideAddress{} + }, + } + + b.ReportAllocs() + b.StopTimer() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StartTimer() + rs, err := CallTreeVerifier(env, tree) + b.StopTimer() + require.NoError(b, err) + require.Equal(b, 5, len(rs.Calls())) + + } +} + +func BenchmarkVmWithDeserialize(b *testing.B) { + source := "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=" + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(b, err) + + tree, err := Parse(src) + require.NoError(b, err) + + script, err := CompileTree("", tree) + require.NoError(b, err) + + ser := NewSerializer() + err = script.Serialize(ser) + require.NoError(b, err) + + bts := ser.Source() + + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + } + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + stateFunc: func() types.SmartState { + return state + }, + thisFunc: func() rideType { + return rideAddress{} + }, + } + + b.ReportAllocs() + b.StopTimer() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StartTimer() + exe, err := DeserializeExecutable(bts) + require.NoError(b, err) + rs, err := exe.Verify(env) + require.Equal(b, 5, len(rs.Calls())) + b.StopTimer() + require.NoError(b, err) + } +} + +func BenchmarkTreeWithDeserialize(b *testing.B) { + source := "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=" + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(b, err) + // + //tree, err := Parse(src) + //require.NoError(b, err) + + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + } + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + stateFunc: func() types.SmartState { + return state + }, + thisFunc: func() rideType { + return rideAddress{} + }, + } + + b.ReportAllocs() + b.StopTimer() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StartTimer() + tree, err := Parse(src) + require.NoError(b, err) + rs, err := CallTreeVerifier(env, tree) + b.StopTimer() + require.NoError(b, err) + require.Equal(b, 5, len(rs.Calls())) + } +} diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index a4aebe6846..a6bbf7e526 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -78,9 +78,6 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP paramIds = append(paramIds, e) params.r.set(args[i], e) } - //if invokeParam != "" { - // assigments = assigments[1:] - //} return &FuncState{ prev: prev, @@ -135,7 +132,6 @@ func (a FuncState) String(value string) Fsm { } func (a FuncState) Condition() Fsm { - //a.lastStmtOffset = a.b.len() return conditionalTransition(a, a.params, a.defers) } @@ -154,7 +150,6 @@ func (a FuncState) Bytes(value []byte) Fsm { func (a FuncState) Func(name string, args []string, invoke string) Fsm { return funcTransition(a, a.params, name, args, invoke) - //panic(fmt.Sprintf("Illegal call `Func` is `FuncState` tx: %s", a.params.txID)) } func (a FuncState) Clean() { diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index d8da78f25b..9b780e9b8c 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -6,21 +6,49 @@ type constid = uint16 type Refs map[uint16]point -type entrypoint struct { +type Entrypoint struct { name string at uint16 argn uint16 } +func (a Entrypoint) Serialize(s Serializer) error { + err := s.String(rideString(a.name)) + if err != nil { + return err + } + s.Uint16(a.at) + s.Uint16(a.argn) + return nil +} + +func deserializeEntrypoint(d *Deserializer) (Entrypoint, error) { + var err error + a := Entrypoint{} + a.name, err = d.String() + if err != nil { + return a, err + } + a.at, err = d.Uint16() + if err != nil { + return a, err + } + a.argn, err = d.Uint16() + if err != nil { + return a, err + } + return a, nil +} + type builder struct { w *bytes.Buffer - entrypoints map[string]entrypoint + entrypoints map[string]Entrypoint } func newBuilder() *builder { return &builder{ w: new(bytes.Buffer), - entrypoints: make(map[string]entrypoint), + entrypoints: make(map[string]Entrypoint), } } @@ -38,7 +66,7 @@ func (b *builder) push(uint162 uint16) { } func (b *builder) setStart(name string, argn int) { - b.entrypoints[name] = entrypoint{ + b.entrypoints[name] = Entrypoint{ name: name, at: b.len(), argn: uint16(argn), @@ -73,6 +101,13 @@ func (b *builder) patch(at uint16, val []byte) { } } +func patchBuffer(b *bytes.Buffer, at uint16, val []byte) { + bts := b.Bytes()[at:] + for i := range val { + bts[i] = val[i] + } +} + func (b *builder) len() uint16 { return uint16(b.w.Len()) } @@ -93,7 +128,7 @@ func (b *builder) call(id uint16, argc uint16) { // b.startAt = uint16(b.w.Len()) //} -func (b *builder) build() (map[string]entrypoint, []byte) { +func (b *builder) build() (map[string]Entrypoint, []byte) { return b.entrypoints, b.w.Bytes() } @@ -110,11 +145,51 @@ func (b *builder) write(i []byte) { } type point struct { - position uint16 `cbor:"0,keyasint"` - value rideType `cbor:"1,keyasint"` - fn uint16 `cbor:"2,keyasint"` - constant bool `cbor:"3,keyasint"` - debugInfo string `cbor:"4,keyasint"` + position uint16 + value rideType + fn uint16 + debugInfo string +} + +func (a point) Serialize(s Serializer) error { + s.Uint16(a.position) + if a.value != nil { + err := a.value.Serialize(s) + if err != nil { + return err + } + } else { + err := s.RideNoValue() + if err != nil { + return err + } + } + + s.Uint16(a.fn) + return nil +} + +func (a point) constant() bool { + return a.position == 0 && a.fn == 0 +} + +func deserializePoint(d *Deserializer) (point, error) { + var a point + var err error + a.position, err = d.Uint16() + if err != nil { + return a, err + } + + a.value, err = d.RideValue() + if err != nil { + return a, err + } + a.fn, err = d.Uint16() + if err != nil { + return a, err + } + return a, nil } type cell struct { @@ -132,7 +207,6 @@ func (a *cell) set(u uniqueid, result rideType, fn uint16, position uint16, cons position: position, value: result, fn: fn, - constant: constant, debugInfo: debug, } } @@ -170,39 +244,47 @@ func (a *references) set(name string, uniq uniqueid) { a.refs[name] = uniq } +func (a *references) pop() *references { + if a.prev != nil { + return a.prev + } + panic("no previous refs") +} + type predefFunc struct { - id uint16 - f rideFunction + name string + f rideFunction +} + +type pfunc struct { + name string + f rideFunction + id uint16 } type predef struct { prev *predef - m map[string]predefFunc + m map[string]pfunc } func newPredef(prev *predef) *predef { return &predef{ prev: prev, - m: make(map[string]predefFunc), + m: make(map[string]pfunc), } } -func newPredefWithValue(prev *predef, name string, id uint16, f rideFunction) *predef { - p := newPredef(prev) - p.set(name, id, f) - return p -} - func (a *predef) set(name string, id uint16, f rideFunction) { - a.m[name] = predefFunc{ - id: id, - f: f, + a.m[name] = pfunc{ + name: name, + id: id, + f: f, } } -func (a *predef) get(name string) (predefFunc, bool) { +func (a *predef) get(name string) (pfunc, bool) { if a == nil { - return predefFunc{}, false + return pfunc{}, false } rs, ok := a.m[name] if ok { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index d098f70d60..abfb86746a 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -44,7 +44,7 @@ func (a MainState) String(s string) Fsm { } type BuildExecutable interface { - BuildExecutable(version int, isDapp bool) *Executable + BuildExecutable(version int, isDapp bool, hasVerifier bool) *Executable } func NewMain(params params) Fsm { @@ -69,18 +69,24 @@ func (a MainState) Return() Fsm { } a.b.ret() - //reversed := reverse(a.body) body := a.body + // empty script, example https://testnet.wavesexplorer.com/tx/DprupHKCwJwRhyhbHyqJqp35CvhiJdpkhjf53z1vmwHr + if len(body) == 0 { + return a + } for { if f, ok := body[0].(FuncState); ok && f.invokeParam != "" { a.b.setStart(f.name, f.argn) + a.b.setStart("", 0) for i := len(f.ParamIds()) - 1; i >= 0; i-- { a.b.writeByte(OpCache) a.b.write(encode(f.ParamIds()[i])) a.b.writeByte(OpPop) } + } else { + a.b.setStart("", 0) } - a.b.setStart("", 0) + body[0].Write(a.params, nil) body = body[1:] if len(body) == 0 { @@ -121,7 +127,7 @@ func (a MainState) Boolean(v bool) Fsm { return a } -func (a MainState) BuildExecutable(version int, isDapp bool) *Executable { +func (a MainState) BuildExecutable(version int, isDapp bool, hasVerifier bool) *Executable { entrypoints, code := a.b.build() return &Executable{ LibVersion: version, @@ -129,6 +135,7 @@ func (a MainState) BuildExecutable(version int, isDapp bool) *Executable { References: a.c.values, EntryPoints: entrypoints, IsDapp: isDapp, + hasVerifier: hasVerifier, } } diff --git a/pkg/ride/constants.go b/pkg/ride/constants.go index 6809f6304f..2a4c3d9fb7 100644 --- a/pkg/ride/constants.go +++ b/pkg/ride/constants.go @@ -90,12 +90,12 @@ func checkConstantV4(name string) (uint16, bool) { return 0, false } -func newFloor(RideEnvironment) rideType { - return rideNamedType{name: "Floor"} +func newSha256(RideEnvironment) rideType { + return rideNamedType{name: "Sha256"} } -func createFloor(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Floor"}, nil +func createSha256(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha256"}, nil } func newSha512(RideEnvironment) rideType { @@ -122,22 +122,6 @@ func createSha3384(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Sha3384"}, nil } -func newHalfEven(RideEnvironment) rideType { - return rideNamedType{name: "HalfEven"} -} - -func createHalfEven(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfEven"}, nil -} - -func newUp(RideEnvironment) rideType { - return rideNamedType{name: "Up"} -} - -func createUp(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Up"}, nil -} - func newSha1(RideEnvironment) rideType { return rideNamedType{name: "Sha1"} } @@ -146,36 +130,36 @@ func createSha1(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Sha1"}, nil } -func newSha3224(RideEnvironment) rideType { - return rideNamedType{name: "Sha3224"} +func newSell(RideEnvironment) rideType { + return rideNamedType{name: "Sell"} } -func createSha3224(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3224"}, nil +func createSell(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sell"}, nil } -func newSha3512(RideEnvironment) rideType { - return rideNamedType{name: "Sha3512"} +func newCeiling(RideEnvironment) rideType { + return rideNamedType{name: "Ceiling"} } -func createSha3512(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3512"}, nil +func createCeiling(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Ceiling"}, nil } -func newSell(RideEnvironment) rideType { - return rideNamedType{name: "Sell"} +func newFloor(RideEnvironment) rideType { + return rideNamedType{name: "Floor"} } -func createSell(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sell"}, nil +func createFloor(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Floor"}, nil } -func newBuy(RideEnvironment) rideType { - return rideNamedType{name: "Buy"} +func newHalfEven(RideEnvironment) rideType { + return rideNamedType{name: "HalfEven"} } -func createBuy(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Buy"}, nil +func createHalfEven(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfEven"}, nil } func newDown(RideEnvironment) rideType { @@ -186,12 +170,28 @@ func createDown(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Down"}, nil } -func newNoAlg(RideEnvironment) rideType { - return rideNamedType{name: "NoAlg"} +func newUp(RideEnvironment) rideType { + return rideNamedType{name: "Up"} } -func createNoAlg(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "NoAlg"}, nil +func createUp(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Up"}, nil +} + +func newHalfUp(RideEnvironment) rideType { + return rideNamedType{name: "HalfUp"} +} + +func createHalfUp(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfUp"}, nil +} + +func newMd5(RideEnvironment) rideType { + return rideNamedType{name: "Md5"} +} + +func createMd5(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Md5"}, nil } func newSha224(RideEnvironment) rideType { @@ -202,50 +202,50 @@ func createSha224(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Sha224"}, nil } -func newSha384(RideEnvironment) rideType { - return rideNamedType{name: "Sha384"} +func newSha3512(RideEnvironment) rideType { + return rideNamedType{name: "Sha3512"} } -func createSha384(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha384"}, nil +func createSha3512(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3512"}, nil } -func newCeiling(RideEnvironment) rideType { - return rideNamedType{name: "Ceiling"} +func newHalfDown(RideEnvironment) rideType { + return rideNamedType{name: "HalfDown"} } -func createCeiling(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Ceiling"}, nil +func createHalfDown(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfDown"}, nil } -func newMd5(RideEnvironment) rideType { - return rideNamedType{name: "Md5"} +func newBuy(RideEnvironment) rideType { + return rideNamedType{name: "Buy"} } -func createMd5(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Md5"}, nil +func createBuy(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Buy"}, nil } -func newSha256(RideEnvironment) rideType { - return rideNamedType{name: "Sha256"} +func newNoAlg(RideEnvironment) rideType { + return rideNamedType{name: "NoAlg"} } -func createSha256(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha256"}, nil +func createNoAlg(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "NoAlg"}, nil } -func newHalfUp(RideEnvironment) rideType { - return rideNamedType{name: "HalfUp"} +func newSha384(RideEnvironment) rideType { + return rideNamedType{name: "Sha384"} } -func createHalfUp(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfUp"}, nil +func createSha384(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha384"}, nil } -func newHalfDown(RideEnvironment) rideType { - return rideNamedType{name: "HalfDown"} +func newSha3224(RideEnvironment) rideType { + return rideNamedType{name: "Sha3224"} } -func createHalfDown(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfDown"}, nil +func createSha3224(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3224"}, nil } diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index b85310fad9..abd899eaa8 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -43,12 +43,27 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "101": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, "-", nodes, f) }, + "103": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, ">=", nodes, f) + }, "104": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, "*", nodes, f) }, "105": 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) + }, + "201": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "take", nodes, f) + }, + "202": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "drop", nodes, f) + }, + "203": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, "+", nodes, f) + }, "300": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, "+", nodes, f) }, @@ -58,18 +73,33 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "401": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "getList", nodes, f) }, + "410": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "toBytes", nodes, f) + }, + "411": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "toBytes", nodes, f) + }, "420": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "toString", nodes, f) }, + "504": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "rsaVerify", nodes, f) + }, "600": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "toBase58String", 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) }, "1052": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "getBinary", nodes, f) }, + "1201": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "toInt", nodes, f) + }, } func defunc(s *strings.Builder, name string, nodes []Node, f detreeType) { diff --git a/pkg/ride/deserializer.go b/pkg/ride/deserializer.go new file mode 100644 index 0000000000..ee7ae9b298 --- /dev/null +++ b/pkg/ride/deserializer.go @@ -0,0 +1,132 @@ +package ride + +import ( + "encoding/binary" + + "github.com/pkg/errors" +) + +type Deserializer struct { + source []byte +} + +func NewDeserializer(source []byte) *Deserializer { + return &Deserializer{source: source} +} + +func (a *Deserializer) readn(n int) ([]byte, error) { + if len(a.source) >= n { + out := a.source[:n] + a.source = a.source[n:] + return out, nil + } + return nil, errors.New("insufficient length") +} + +func (a *Deserializer) Uint16() (uint16, error) { + b, err := a.readn(2) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint16(b), nil +} + +func (a *Deserializer) Byte() (byte, error) { + b, err := a.readn(1) + if err != nil { + return 0, err + } + return b[0], nil +} + +func (a *Deserializer) Bool() (bool, error) { + b, err := a.Byte() + if err != nil { + return false, err + } + switch b { + case strue: + return true, nil + case sfalse: + return false, nil + default: + return false, errors.New("unknown byte") + } +} + +func (a *Deserializer) Bytes() ([]byte, error) { + ln, err := a.Uint16() + if err != nil { + return nil, err + } + return a.readn(int(ln)) +} + +func (a *Deserializer) Map() (uint16, error) { + b, err := a.Byte() + if err != nil { + return 0, err + } + if b != sMap { + return 0, errors.Errorf("expected `Map` byte, found %d", b) + } + size, err := a.Uint16() + return size, err +} + +func (a *Deserializer) RideString() (string, error) { + b, err := a.Byte() + if err != nil { + return "", err + } + if b != sString { + return "", errors.Errorf("expected `String` byte %d, found %d", sString, b) + } + return a.String() +} + +func (a *Deserializer) String() (string, error) { + bts, err := a.Bytes() + if err != nil { + return "", err + } + return string(bts), nil +} + +func (a *Deserializer) Int64() (int64, error) { + bts, err := a.readn(8) + if err != nil { + return 0, err + } + v := binary.BigEndian.Uint64(bts) + return int64(v), nil +} + +func (a *Deserializer) RideValue() (rideType, error) { + b, err := a.Byte() + if err != nil { + return nil, err + } + switch b { + case sNoValue: + return nil, nil + case strue: + return rideBoolean(true), nil + case sfalse: + return rideBoolean(false), nil + case sint: + v, err := a.Int64() + return rideInt(v), err + case sString: + v, err := a.String() + return rideString(v), err + case sbytes: + v, err := a.Bytes() + return rideBytes(v), err + default: + if b <= 100 { + return rideInt(b), nil + } + return nil, errors.Errorf("unknown type %d", b) + } +} diff --git a/pkg/ride/deserializer_test.go b/pkg/ride/deserializer_test.go new file mode 100644 index 0000000000..e2456780c7 --- /dev/null +++ b/pkg/ride/deserializer_test.go @@ -0,0 +1,56 @@ +package ride + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSerialization(t *testing.T) { + t.Run("uint16", func(t *testing.T) { + s := NewSerializer() + s.Uint16(10) + + d := NewDeserializer(s.Source()) + rs, _ := d.Uint16() + require.Equal(t, uint16(10), rs) + }) + t.Run("string", func(t *testing.T) { + s := NewSerializer() + s.RideString("some string") + + d := NewDeserializer(s.Source()) + rs, _ := d.RideString() + require.Equal(t, "some string", rs) + }) + t.Run("entrypoint", func(t *testing.T) { + e := Entrypoint{ + name: "name", + at: 1050, + argn: 2, + } + s := NewSerializer() + err := e.Serialize(s) + require.NoError(t, err) + + d := NewDeserializer(s.Source()) + e2, err := deserializeEntrypoint(d) + require.NoError(t, err) + require.Equal(t, e, e2) + }) + t.Run("point", func(t *testing.T) { + e := point{ + position: 1050, + value: rideString("ss"), + fn: 1, + } + s := NewSerializer() + err := e.Serialize(s) + require.NoError(t, err) + + d := NewDeserializer(s.Source()) + e2, err := deserializePoint(d) + require.NoError(t, err) + require.Equal(t, e, e2) + }) +} diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index c0a35a4bc6..6ff4d90e94 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -1,28 +1,53 @@ package ride import ( - "io" - "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" ) type Executable struct { LibVersion int + IsDapp bool + hasVerifier bool ByteCode []byte - EntryPoints map[string]entrypoint + EntryPoints map[string]Entrypoint References map[uniqueid]point - IsDapp bool } -func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (RideResult, error) { - vm, err := a.makeVm(environment, int(a.EntryPoints[""].at), arguments) +func (a *Executable) HasVerifier() bool { + return a.hasVerifier +} + +func (a *Executable) Verify(environment RideEnvironment) (RideResult, error) { + if a.IsDapp { + if !a.HasVerifier() { + return nil, errors.Errorf("no verifier attached to script") + } + return a.runWithoutChecks(environment, "", []rideType{environment.transaction()}) + } + return a.runWithoutChecks(environment, "", nil) +} + +func (a *Executable) Entrypoint(name string) (Entrypoint, error) { + v, ok := a.EntryPoints[name] + if !ok { + return Entrypoint{}, errors.Errorf("entrypoint %s not found", name) + } + return v, nil +} + +func (a *Executable) runWithoutChecks(environment RideEnvironment, name string, arguments []rideType) (RideResult, error) { + fcall, ok := a.EntryPoints[name] + if !ok { + return nil, errors.Errorf("function %s not found", name) + } + vm, err := a.makeVm(environment, int(fcall.at), arguments) if err != nil { return nil, err } v, err := vm.run() if err != nil { - return nil, err + return ScriptResult{res: false, msg: "", calls: vm.calls, refs: vm.ref}, err } switch tv := v.(type) { case rideThrow: @@ -49,11 +74,14 @@ func (a *Executable) Run(environment RideEnvironment, arguments []rideType) (Rid } return DAppResult{res: true, actions: actions, calls: vm.calls, refs: vm.ref}, nil default: - return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) + return ScriptResult{calls: vm.calls}, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) } } -func (a *Executable) Run2(environment RideEnvironment, name string, arguments []rideType) (RideResult, error) { +func (a *Executable) Invoke(environment RideEnvironment, name string, arguments []rideType) (RideResult, error) { + if name == "" { + return nil, errors.Errorf("expected func name, found \"\"") + } fcall, ok := a.EntryPoints[name] if !ok { return nil, errors.Errorf("function %s not found", name) @@ -61,84 +89,146 @@ func (a *Executable) Run2(environment RideEnvironment, name string, arguments [] if len(arguments) != int(fcall.argn)+1 { return nil, errors.Errorf("func `%s` requires %d arguments(1 invoke + %d args), but provided %d", name, fcall.argn+1, fcall.argn, len(arguments)) } - vm, err := a.makeVm(environment, int(fcall.at), arguments) + return a.runWithoutChecks(environment, name, arguments) +} + +func (a *Executable) run(environment RideEnvironment, arguments []rideType) (rideType, error) { + vm, err := a.makeVm(environment, int(a.EntryPoints[""].at), arguments) if err != nil { return nil, err } - //vm := &vm{ - // code: a.ByteCode, - // ip: int(fcall.at), - // functions: fSelect, - // functionName: provider, - // env: environment, - // ref: a.References, - // stack: arguments, - //} - //if err != nil { - // return nil, err - //} - v, err := vm.run() + return vm.run() +} + +func (a *Executable) makeVm(environment RideEnvironment, entrypoint int, arguments []rideType) (*vm, error) { + refs := copyReferences(a.References) + return &vm{ + code: a.ByteCode, + ip: entrypoint, + env: environment, + ref: refs, + stack: arguments, + jmps: []int{1}, + libVersion: a.LibVersion, + }, nil +} + +func (a *Executable) Serialize(s Serializer) error { + s.Byte(202) + s.Uint16(uint16(a.LibVersion)) + s.Bool(a.IsDapp) + s.Bool(a.hasVerifier) + err := s.Bytes(a.ByteCode) if err != nil { - return nil, err + return err } - switch tv := v.(type) { - case rideThrow: - if a.IsDapp { - return DAppResult{res: false, msg: string(tv), calls: vm.calls}, nil - } - return ScriptResult{res: false, msg: string(tv), calls: vm.calls}, nil - case rideBoolean: - return ScriptResult{res: bool(tv), operations: vm.numOperations, calls: vm.calls}, nil - case rideObject: - actions, err := objectToActions(vm.env, tv) - if err != nil { - return nil, errors.Wrap(err, "failed to convert evaluation result") + // entrypoints + err = s.Map(len(a.EntryPoints), func(m Map) error { + for k, v := range a.EntryPoints { + err := m.RideString(rideString(k)) + if err != nil { + return err + } + err = v.Serialize(s) + if err != nil { + return err + } } - return DAppResult{res: true, actions: actions, msg: "", calls: vm.calls}, nil - case rideList: - actions := make([]proto.ScriptAction, len(tv)) - for i, item := range tv { - a, err := convertToAction(vm.env, item) + return nil + }) + if err != nil { + return err + } + // references + err = s.Map(len(a.References), func(m Map) error { + for k, v := range a.References { + m.Uint16(k) + err := v.Serialize(s) if err != nil { - return nil, errors.Wrap(err, "failed to convert evaluation result") + return err } - actions[i] = a } - return DAppResult{res: true, actions: actions, calls: vm.calls}, nil - default: - return nil, errors.Errorf("unexpected result value '%v' of type '%T'", v, v) + return nil + }) + if err != nil { + return err } + return nil } -func (a *Executable) run(environment RideEnvironment, arguments []rideType) (rideType, error) { - vm, err := a.makeVm(environment, int(a.EntryPoints[""].at), arguments) +func DeserializeExecutable(source []byte) (*Executable, error) { + d := NewDeserializer(source) + magic, err := d.Byte() if err != nil { return nil, err } - return vm.run() -} - -func (a *Executable) makeVm(environment RideEnvironment, entrypoint int, arguments []rideType) (*vm, error) { - fSelect, err := selectFunctions(a.LibVersion) + if magic != 202 { + return nil, errors.New("invalid magic number") + } + libVersion, err := d.Uint16() if err != nil { return nil, err } - provider, err := selectFunctionNameProvider(a.LibVersion) + isDapp, err := d.Bool() if err != nil { return nil, err } - return &vm{ - code: a.ByteCode, - ip: int(a.EntryPoints[""].at), - functions: fSelect, - functionName: provider, - env: environment, - ref: a.References, - stack: arguments, - jmps: []int{1}, + hasVerifier, err := d.Bool() + if err != nil { + return nil, err + } + byteCode, err := d.Bytes() + if err != nil { + return nil, err + } + size, err := d.Map() + if err != nil { + return nil, err + } + entrypoints := make(map[string]Entrypoint, size) + for i := uint16(0); i < size; i++ { + name, err := d.RideString() + if err != nil { + return nil, err + } + entrypoint, err := deserializeEntrypoint(d) + if err != nil { + return nil, err + } + entrypoints[name] = entrypoint + } + + size, err = d.Map() + if err != nil { + return nil, err + } + references := make(map[uniqueid]point, size) + for i := uint16(0); i < size; i++ { + id, err := d.Uint16() + if err != nil { + return nil, err + } + p, err := deserializePoint(d) + if err != nil { + return nil, err + } + references[id] = p + } + + return &Executable{ + LibVersion: int(libVersion), + IsDapp: isDapp, + ByteCode: byteCode, + hasVerifier: hasVerifier, + EntryPoints: entrypoints, + References: references, }, nil } -func (a *Executable) WriteTo(w io.Writer) (int64, error) { - panic("Executable WriteTo") +func copyReferences(refs Refs) Refs { + out := make(Refs, len(refs)) + for k, v := range refs { + out[k] = v + } + return out } diff --git a/pkg/ride/executable_test.go b/pkg/ride/executable_test.go new file mode 100644 index 0000000000..ea30ad7f3d --- /dev/null +++ b/pkg/ride/executable_test.go @@ -0,0 +1,30 @@ +package ride + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestExecutableSerialization(t *testing.T) { + source := `AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + script, err := CompileTree("", tree) + require.NoError(t, err) + + s := NewSerializer() + + err = script.Serialize(s) + require.NoError(t, err) + + script2, err := DeserializeExecutable(s.Source()) + require.NoError(t, err) + + require.Equal(t, script, script2) +} diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index df339feadb..aafca92f22 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -9,15 +9,6 @@ func tx(env RideEnvironment, _ ...rideType) (rideType, error) { return env.transaction(), nil } -//func mergeWithPredefined(f func(id int) rideFunction, p *predef) func(id int) rideFunction { -// return func(id int) rideFunction { -// if c := p.getn(id); c != nil { -// return c -// } -// return f(id) -// } -//} - func this(env RideEnvironment, _ ...rideType) (rideType, error) { return env.this(), nil } @@ -31,25 +22,35 @@ func nilFunc(env RideEnvironment, _ ...rideType) (rideType, error) { return out, nil } -func retRideType() rideList { - return nil -} - func lastBlock(env RideEnvironment, _ ...rideType) (rideType, error) { return env.block(), nil } -var predefinedFunctions = map[string]predefFunc{ - "tx": {id: math.MaxUint16 - 0, f: tx}, - "unit": {id: math.MaxUint16 - 1, f: unit}, - "NOALG": {id: math.MaxUint16 - 2, f: createNoAlg}, - "this": {id: math.MaxUint16 - 3, f: this}, - "height": {id: math.MaxUint16 - 4, f: height}, - "nil": {id: math.MaxUint16 - 5, f: nilFunc}, - "lastBlock": {id: math.MaxUint16 - 6, f: lastBlock}, - "UP": {id: math.MaxUint16 - 7, f: createUp}, - "DOWN": {id: math.MaxUint16 - 8, f: createDown}, - "HALFDOWN": {id: math.MaxUint16 - 9, f: createHalfDown}, +// Order is important! Only add, avoid changes. +var predefinedFunctions = []predefFunc{ + {"tx", tx}, + {"unit", unit}, + {"NOALG", createNoAlg}, + {"this", this}, + {"height", height}, + {"nil", nilFunc}, + {"lastBlock", lastBlock}, + {"UP", createUp}, + {"DOWN", createDown}, + {"HALFDOWN", createHalfDown}, + {"HALFUP", createHalfUp}, + {"MD5", createMd5}, + {"SHA1", createSha1}, + {"SHA224", createSha224}, + {"SHA256", createSha256}, + {"SHA384", createSha384}, + {"SHA512", createSha512}, + {"SHA3224", createSha3224}, + {"SHA3256", createSha3256}, + {"SHA3384", createSha3384}, + {"SHA3512", createSha3512}, + {"Buy", createBuy}, + {"Sell", createSell}, } var predefined *predef @@ -57,6 +58,6 @@ var predefined *predef func init() { predefined = newPredef(nil) for k, v := range predefinedFunctions { - predefined.set(k, v.id, v.f) + predefined.set(v.name, uint16(math.MaxUint16-k), v.f) } } diff --git a/pkg/ride/generate/main.go b/pkg/ride/generate/main.go index d71baab222..b122edf995 100644 --- a/pkg/ride/generate/main.go +++ b/pkg/ride/generate/main.go @@ -721,6 +721,14 @@ func createTuples(sb *strings.Builder) { sb.WriteString("}\n") sb.WriteString(fmt.Sprintf("return %s\n", strings.Join(comparisons, " && "))) sb.WriteString("}\n\n") + // serialize + sb.WriteString(fmt.Sprintf("func (a tuple%d) Serialize(serializer Serializer) error {\n", n)) + sb.WriteString(" return serializer.Tuple(") + for i := 1; i <= n; i++ { + sb.WriteString(fmt.Sprintf("a.el%d,", i)) + } + sb.WriteString(")\n}\n") + } } diff --git a/pkg/ride/opcodes.go b/pkg/ride/opcodes.go index 96b3d0bfc7..74e9b21abf 100644 --- a/pkg/ride/opcodes.go +++ b/pkg/ride/opcodes.go @@ -14,7 +14,7 @@ const ( OpJumpIfFalse //07 - Moves instruction pointer to new position if value on stack is False. One parameter: new position. OpProperty //08 - Puts value of object's property on stack. One parameter: constant ID that holds name of the property. OpExternalCall //09 - Call a standard library function. Two parameters: function ID, number of arguments. - OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration. + OpCall //10 Obsolete! 0xa - Call a function declared at given address. One parameter: position of function declaration. OpSetArg //11 0xb - FROM (global) -> TO (local): Set value into cell. Two parameters: constant id and cell id. OpCache //12 0xc - Put constant on stack. One parameter: constant ID. OpRef //13 0xd = ref id diff --git a/pkg/ride/reverse_tree.go b/pkg/ride/reverse_tree.go index 2eaae585bd..757451d0c3 100644 --- a/pkg/ride/reverse_tree.go +++ b/pkg/ride/reverse_tree.go @@ -1,7 +1,11 @@ package ride import ( + "bytes" "fmt" + "math" + + "github.com/pkg/errors" ) func ReverseTree(n []Node) { @@ -74,52 +78,638 @@ func reverseTree(n Node, r []*RLet) RNode { // //} -//func compileArguments(call *RCall, out *bytes.Buffer) { -// d := []RNode{ -// call, +type startpoint struct { + fns []func() + default_ func() +} + +func (a *startpoint) push(f func()) { + a.fns = append(a.fns, f) +} + +func (a *startpoint) evalAndPop() { + if len(a.fns) > 0 { + a.fns[len(a.fns)-1]() + a.fns = a.fns[:len(a.fns)-1] + } else { + a.default_() + } + +} + +//func compileReversedTree(nodes []RNode, libVersion int, isDapp bool, hasVerifier bool) (*Executable, error) { +// var condPos []uint16 +// refs := newReferences(nil) +// out := bytes.Buffer{} +// out.WriteByte(OpReturn) +// out.WriteByte(OpReturn) +// c := newCell() +// u := uniqid{} +// u.next() +// entrypoints := make(map[string]Entrypoint) +// +// st := startpoint{ +// default_: func() { +// entrypoints[""] = Entrypoint{ +// name: "", +// at: uint16(out.Len()), +// argn: 0, +// } +// }, // } -// for i := len(call.Arguments) - 1; i >= 0; i-- { -// switch call.Arguments[i].(type) { -// case *RLong: -// d = append(d, RLong{}) +// st.evalAndPop() +// +// for k, v := range predefinedFunctions { +// id := uint16(math.MaxUint16 - k) +// refs.set(v.name, id) +// c.set(id, nil, id, 0, false, v.name) +// } +// +// // +// for _, v := range nodes { +// switch v := v.(type) { +// case *RDef: +// n := u.next() +// refs.set(v.Name, n) +// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) +// for range v.Arguments { +// u.next() +// } +// case *RConst: +// n := u.next() +// c.set(n, v.Value, 0, 0, true, fmt.Sprintf("constant %q", v.Value)) +// out.WriteByte(OpRef) +// out.Write(encode(n)) +// case *RCall: +// if n, ok := refs.get(v.Name); ok { +// out.WriteByte(OpRef) +// out.Write(encode(n)) +// continue +// } +// fCheck, err := selectFunctionChecker(libVersion) +// if err != nil { +// return nil, err +// } +// out.WriteByte(OpExternalCall) +// id, ok := fCheck(v.Name) +// if !ok { +// return nil, errors.Errorf("invalid func name `%s`", v.Name) +// } +// out.Write(encode(id)) +// out.Write(encode(v.Argn)) +// case *RReferenceNode: +// n, ok := refs.get(v.Name) +// if !ok { +// return nil, errors.Errorf("reference `%s` not found", v.Name) +// } +// out.WriteByte(OpRef) +// out.Write(encode(n)) +// case *RLet: +// n := u.next() +// refs.set(v.Name, n) +// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) +// n, ok := refs.get(v.Name) +// if !ok { +// return nil, errors.Errorf("reference `%s` not found", v.Name) +// } +// e, ok := c.values[n] +// if !ok { +// return nil, errors.Errorf("cell `%d` not found", n) +// } +// e.position = uint16(out.Len()) +// c.values[n] = e +// case *RFunc: +// n := u.next() +// refs.set(v.Name, n) +// refs = newReferences(refs) +// c.set(n, nil, 0, 0, false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) +// for i := range v.ArgumentsWithInvocation { +// z := u.next() +// c.set(z, nil, 0, 0, false, fmt.Sprintf("ref %d, func arg #%d %s", z, i, v.Name)) +// refs.set(v.ArgumentsWithInvocation[i], z) +// } +// if v.Invocation != "" { +// st.push(func() { +// entrypoints[v.Name] = Entrypoint{ +// name: v.Name, +// at: uint16(out.Len()), +// argn: uint16(len(v.Arguments)), +// } +// for i := len(v.Arguments) + 1; i > 0; i-- { +// out.WriteByte(OpCache) +// out.Write(encode(n + uint16(i))) +// out.WriteByte(OpPop) +// } +// }) +// } else { +// st.push(func() { +// c.set(n, nil, 0, uint16(out.Len()), false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) +// for i := len(v.ArgumentsWithInvocation); i > 0; i-- { +// out.WriteByte(OpCache) +// out.Write(encode(n + uint16(i))) +// out.WriteByte(OpPop) +// } +// }) +// } +// case *RFuncEnd: +// refs = refs.pop() +// +// case *RRet: +// out.WriteByte(OpReturn) +// case *RCond: +// condPos = append(condPos, uint16(out.Len())) +// out.WriteByte(OpJumpIfFalse) +// out.Write(make([]byte, 6)) +// case *RCondTrue: +// pos := condPos[len(condPos)-1] +// st.push(func() { +// patchBuffer(&out, pos+1, encode(uint16(out.Len()))) +// }) +// case *RCondFalse: +// pos := condPos[len(condPos)-1] +// st.push(func() { +// patchBuffer(&out, pos+3, encode(uint16(out.Len()))) +// }) +// +// case *RCondEnd: +// pos := condPos[len(condPos)-1] +// patchBuffer(&out, pos+5, encode(uint16(out.Len()))) +// condPos = condPos[:len(condPos)-1] +// case *RStart: +// st.evalAndPop() +// +// case *RProperty: +// out.WriteByte(OpProperty) +// +// default: +// panic(fmt.Sprintf("unknown type %T", v)) // } +// // } +// +// // Most recent code line. +// out.WriteByte(OpReturn) +// +// if isDapp && hasVerifier { +// entrypoints[""] = entrypoints["verify"] +// } +// +// e := Executable{ +// LibVersion: libVersion, +// IsDapp: isDapp, +// hasVerifier: hasVerifier, +// ByteCode: out.Bytes(), +// EntryPoints: entrypoints, +// References: c.values, +// } +// +// return &e, nil //} -func reverseTree2(n Node, out []RNode, deferreds []RNode) []RNode { +func compileReversedTree(nodes []RNode, libVersion int, isDapp bool, hasVerifier bool) (*Executable, error) { + var condPos []uint16 + refs := newReferences(nil) + out := bytes.Buffer{} + out.WriteByte(OpReturn) + out.WriteByte(OpReturn) + c := newCell() + u := uniqid{} + u.next() + entrypoints := make(map[string]Entrypoint) + + st := startpoint{ + default_: func() { + entrypoints[""] = Entrypoint{ + name: "", + at: uint16(out.Len()), + argn: 0, + } + }, + } + st.evalAndPop() + + for k, v := range predefinedFunctions { + id := uint16(math.MaxUint16 - k) + refs.set(v.name, id) + c.set(id, nil, id, 0, false, v.name) + } + + // + for _, v := range nodes { + switch v := v.(type) { + case *RDef: + n := u.next() + refs.set(v.Name, n) + c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) + for range v.Arguments { + u.next() + } + //case *RBody: + // n, ok := refs.get(v.Name, n) + // if !ok { + // return errors.Errorf() + // } + case *RConst: + n := u.next() + c.set(n, v.Value, 0, 0, true, fmt.Sprintf("constant %q", v.Value)) + out.WriteByte(OpRef) + out.Write(encode(n)) + case *RCall: + if n, ok := refs.get(v.Name); ok { + out.WriteByte(OpRef) + out.Write(encode(n)) + continue + } + fCheck, err := selectFunctionChecker(libVersion) + if err != nil { + return nil, err + } + out.WriteByte(OpExternalCall) + id, ok := fCheck(v.Name) + if !ok { + return nil, errors.Errorf("invalid func name `%s`", v.Name) + } + out.Write(encode(id)) + out.Write(encode(v.Argn)) + case *RReferenceNode: + n, ok := refs.get(v.Name) + if !ok { + return nil, errors.Errorf("reference `%s` not found", v.Name) + } + out.WriteByte(OpRef) + out.Write(encode(n)) + case *RLet: + n := u.next() + refs.set(v.Name, n) + c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) + n, ok := refs.get(v.Name) + if !ok { + return nil, errors.Errorf("reference `%s` not found", v.Name) + } + e, ok := c.values[n] + if !ok { + return nil, errors.Errorf("cell `%d` not found", n) + } + e.position = uint16(out.Len()) + c.values[n] = e + case *RFunc: + n := u.next() + refs.set(v.Name, n) + refs = newReferences(refs) + c.set(n, nil, 0, 0, false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) + for i := range v.ArgumentsWithInvocation { + z := u.next() + c.set(z, nil, 0, 0, false, fmt.Sprintf("ref %d, func arg #%d %s", z, i, v.Name)) + refs.set(v.ArgumentsWithInvocation[i], z) + } + if v.Invocation != "" { + st.push(func() { + entrypoints[v.Name] = Entrypoint{ + name: v.Name, + at: uint16(out.Len()), + argn: uint16(len(v.Arguments)), + } + for i := len(v.Arguments) + 1; i > 0; i-- { + out.WriteByte(OpCache) + out.Write(encode(n + uint16(i))) + out.WriteByte(OpPop) + } + }) + } else { + st.push(func() { + c.set(n, nil, 0, uint16(out.Len()), false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) + for i := len(v.ArgumentsWithInvocation); i > 0; i-- { + out.WriteByte(OpCache) + out.Write(encode(n + uint16(i))) + out.WriteByte(OpPop) + } + }) + } + case *RFuncEnd: + refs = refs.pop() + + case *RRet: + out.WriteByte(OpReturn) + case *RCond: + condPos = append(condPos, uint16(out.Len())) + out.WriteByte(OpJumpIfFalse) + out.Write(make([]byte, 6)) + case *RCondTrue: + pos := condPos[len(condPos)-1] + st.push(func() { + patchBuffer(&out, pos+1, encode(uint16(out.Len()))) + }) + case *RCondFalse: + pos := condPos[len(condPos)-1] + st.push(func() { + patchBuffer(&out, pos+3, encode(uint16(out.Len()))) + }) + + case *RCondEnd: + pos := condPos[len(condPos)-1] + patchBuffer(&out, pos+5, encode(uint16(out.Len()))) + condPos = condPos[:len(condPos)-1] + case *RStart: + st.evalAndPop() + + case *RProperty: + out.WriteByte(OpProperty) + + default: + panic(fmt.Sprintf("unknown type %T", v)) + } + + } + + // Most recent code line. + out.WriteByte(OpReturn) + + if isDapp && hasVerifier { + entrypoints[""] = entrypoints["verify"] + } + + e := Executable{ + LibVersion: libVersion, + IsDapp: isDapp, + hasVerifier: hasVerifier, + ByteCode: out.Bytes(), + EntryPoints: entrypoints, + References: c.values, + } + + return &e, nil +} + +type ddfrs struct { +} + +/* +func reverseTree2(n Node, out []RNode, deferreds *ddfrs) []RNode { switch t := n.(type) { case *FunctionDeclarationNode: - out = append(out, &RFunc{Name: t.Name, Arguments: t.Arguments, Invocation: t.invocationParameter}) - return reverseTree2(t.Body, out, nil) + out = append(out, &RDef{Name: t.Name, Arguments: t.Arguments}) + temp := []RNode{&RFunc{Name: t.Name, Arguments: t.Arguments, Invocation: t.invocationParameter}} + // func body + d := &ddfrs{} + temp = append(temp, reverseTree2(t.Body, nil, d)...) + // end of function + temp = append(temp, &RFuncEnd{}) + temp = append(temp, &RRet{}) + temp = append(temp, d.deferreds...) + return reverseTree2(t.Block, out, deferreds) case *AssignmentNode: - return reverseTree2(t.Block, out, append(deferreds, &RLet{Name: t.Name, Body: reverseTree2(t.Expression, nil, nil)})) + out = append([]RNode{&RDef{Name: t.Name}}, out...) + deferreds.add(&RLet{Name: t.Name}) + //d := &ddfrs{} + deferreds = reverseTree2(t.Expression, nil, deferreds) + deferreds = append(deferreds, &RRet{}) + return reverseTree2(t.Block, out, deferreds) + case *ConditionalNode: + cond := reverseTree2(t.Condition, nil, nil) + out = append(out, cond...) + out = append(out, &RCond{}) + out = append(out, &RCondTrue{}) + out = append(out, reverseTree2(t.TrueExpression, nil, nil)...) + out = append(out, &RRet{}) + out = append(out, &RCondFalse{}) + out = append(out, reverseTree2(t.FalseExpression, nil, nil)...) + out = append(out, &RRet{}) + out = append(out, &RCondEnd{}) + //if len(deferreds) > 0 { + // out = append(out, &RRet{}) + //} + //return append(out, deferreds...) + return out case *LongNode: - return append(out, &RLong{Value: t.Value}) + return append(out, &RConst{Value: rideInt(t.Value)}) case *FunctionCallNode: - out = append(out, reverseRnodes(flatCall(t))...) + out = append(out, flatCall(t)...) + if len(deferreds) > 0 { + out = append(out, &RRet{}) + } return append(out, deferreds...) + case *BooleanNode: + return append(out, &RConst{Value: rideBoolean(t.Value)}) + case *StringNode: + return append(out, &RConst{Value: rideString(t.Value)}) + case *BytesNode: + return append(out, &RConst{Value: rideBytes(t.Value)}) + case *ReferenceNode: + return append(append(out, &RReferenceNode{Name: t.Name}), deferreds...) default: panic(fmt.Sprintf("unknown type %T", n)) } } +*/ -func flatCall(call *FunctionCallNode) []RNode { - out := []RNode{ - &RCall{ - Name: call.Name, - }, +// Check is definition. +func isDef(n []RNode) bool { + switch n[0].(type) { + case *RLet, *RFunc: + return true + default: + return false } - for i := len(call.Arguments) - 1; i >= 0; i-- { - switch t := call.Arguments[i].(type) { +} + +func appendInvocation(i string, args []string) []string { + if i != "" { + return append([]string{i}, args...) + } + return args +} + +func reverseTree3(n Node, out []RNode) []RNode { + switch t := n.(type) { + case *FunctionDeclarationNode: + out = append(out, &RFunc{ + Name: t.Name, + Arguments: t.Arguments, + Invocation: t.invocationParameter, + ArgumentsWithInvocation: appendInvocation(t.invocationParameter, t.Arguments), + }) + // func body + temp := reverseTree3(t.Body, nil) + if !isDef(temp) { + temp = append([]RNode{&RStart{}}, temp...) + } + out = append(out, temp...) + out = append(out, &RFuncEnd{}) + out = append(out, &RRet{}) + switch t.Block.(type) { + case *AssignmentNode, *FunctionDeclarationNode, nil: + return append(out, reverseTree3(t.Block, nil)...) + default: + out = append(out, &RStart{}) + return append(out, reverseTree3(t.Block, nil)...) + } + case *BooleanNode: + return append(out, &RConst{Value: rideBoolean(t.Value)}) + case *AssignmentNode: + out = append(out, &RLet{Name: t.Name}) + out = append(out, reverseTree3(t.Expression, nil)...) + out = append(out, &RRet{}) + switch t.Block.(type) { + case *AssignmentNode: + return append(out, reverseTree3(t.Block, nil)...) + case *FunctionDeclarationNode: + return append(out, reverseTree3(t.Block, nil)...) + default: + out = append(out, &RStart{}) + return append(out, reverseTree3(t.Block, nil)...) + } + case *LongNode: + return append(out, &RConst{Value: rideInt(t.Value)}) + case *StringNode: + return append(out, &RConst{Value: rideString(t.Value)}) + case *BytesNode: + return append(out, &RConst{Value: rideBytes(t.Value)}) + case *ReferenceNode: + return append(out, &RReferenceNode{Name: t.Name}) + case *FunctionCallNode: + out = append(out, flatCall2(t.Arguments)...) + out = append(out, &RCall{ + Name: t.Name, + Argn: uint16(len(t.Arguments)), + }) + return out + case *ConditionalNode: + out = append(out, flatCondNode(t)...) + return out + case *PropertyNode: + out = append(out, flatProperty(t)...) + return out + case nil: + return nil + default: + panic(fmt.Sprintf("unknown type %T", n)) + } +} + +func CompileFlatTree(tree *Tree) (*Executable, error) { + if tree.IsDApp() { + var rev []RNode + for _, v := range tree.Declarations { + rev = append(rev, reverseTree3(v, nil)...) + } + for _, v := range tree.Functions { + rev = append(rev, reverseTree3(v, nil)...) + } + if tree.HasVerifier() { + rev = append(rev, reverseTree3(tree.Verifier, nil)...) + } + return compileReversedTree(rev, tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) + } + return compileReversedTree(reverseTree3(tree.Verifier, nil), tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) +} + +func flatCondNode(t *ConditionalNode) []RNode { + var out []RNode + cond := reverseTree3(t.Condition, nil) + out = append(out, cond...) + out = append(out, &RCond{}) + out = append(out, &RCondTrue{}) + switch t.TrueExpression.(type) { + case *AssignmentNode: + out = append(out, reverseTree3(t.TrueExpression, nil)...) + default: + out = append(out, &RStart{}) + out = append(out, reverseTree3(t.TrueExpression, nil)...) + } + out = append(out, &RRet{}) + out = append(out, &RCondFalse{}) + switch t.FalseExpression.(type) { + case *AssignmentNode: + out = append(out, reverseTree3(t.FalseExpression, nil)...) + default: + out = append(out, &RStart{}) + out = append(out, reverseTree3(t.FalseExpression, nil)...) + } + out = append(out, &RRet{}) + out = append(out, &RCondEnd{}) + return out +} + +//func flatCall(call *FunctionCallNode) []RNode { +// out := []RNode{ +// &RCall{ +// Name: call.Name, +// Argn: uint16(len(call.Arguments)), +// }, +// } +// for i := len(call.Arguments) - 1; i >= 0; i-- { +// switch t := call.Arguments[i].(type) { +// case *LongNode: +// out = append(out, &RConst{Value: rideInt(t.Value)}) +// case *BooleanNode: +// out = append(out, &RConst{Value: rideBoolean(t.Value)}) +// case *BytesNode: +// out = append(out, &RConst{Value: rideBytes(t.Value)}) +// case *StringNode: +// out = append(out, &RConst{Value: rideString(t.Value)}) +// case *FunctionCallNode: +// out = append(out, flatCall(t)...) +// case *ReferenceNode: +// out = append(out, &RReferenceNode{Name: t.Name}) +// case *PropertyNode: +// out = append(out, reverseRnodes(flatProperty(t))...) +// case *ConditionalNode: +// out = append(out, reverseRnodes(flatCondNode(t))...) +// default: +// panic(fmt.Sprintf("unknown type %T", call.Arguments[i])) +// } +// } +// return out +//} + +func flatCall2(Arguments []Node) []RNode { + var out = []RNode{} + for i := len(Arguments) - 1; i >= 0; i-- { + switch t := Arguments[i].(type) { case *LongNode: - out = append(out, &RLong{Value: t.Value}) + out = append([]RNode{&RConst{Value: rideInt(t.Value)}}, out...) + case *BooleanNode: + out = append([]RNode{&RConst{Value: rideBoolean(t.Value)}}, out...) + case *BytesNode: + out = append([]RNode{&RConst{Value: rideBytes(t.Value)}}, out...) + case *StringNode: + out = append([]RNode{&RConst{Value: rideString(t.Value)}}, out...) case *FunctionCallNode: - out = append(out, flatCall(t)...) + call := flatCall2(t.Arguments) + call = append(call, &RCall{ + Name: t.Name, + Argn: t.ArgumentsCount(), + }) + out = append(call, out...) case *ReferenceNode: - out = append(out, &RRef{Name: t.Name}) + out = append([]RNode{&RReferenceNode{Name: t.Name}}, out...) + case *PropertyNode: + tmp := flatProperty(t) + out = append(tmp, out...) + case *ConditionalNode: + tmp := flatCondNode(t) + out = append(tmp, out...) default: - panic(fmt.Sprintf("unknown type %T", call.Arguments[i])) + panic(fmt.Sprintf("unknown type %T", Arguments[i])) } } return out } + +func flatProperty(p *PropertyNode) []RNode { + switch v := p.Object.(type) { + case *ReferenceNode: + return []RNode{&RReferenceNode{Name: v.Name}, &RConst{Value: rideString(p.Name)}, &RProperty{}} + case *PropertyNode: + return append(flatProperty(v), &RConst{Value: rideString(p.Name)}, &RProperty{}) + case *FunctionCallNode: + call := flatCall2(v.Arguments) + call = append(call, &RCall{ + Name: v.Name, + Argn: v.ArgumentsCount(), + }) + return append(call, &RConst{Value: rideString(p.Name)}, &RProperty{}) + default: + panic(fmt.Sprintf("unknown type %T", v)) + } +} diff --git a/pkg/ride/reverse_tree_test.go b/pkg/ride/reverse_tree_test.go index f026c65442..003e9a2dce 100644 --- a/pkg/ride/reverse_tree_test.go +++ b/pkg/ride/reverse_tree_test.go @@ -1,11 +1,121 @@ package ride import ( + "encoding/base64" + "strconv" "testing" + "github.com/pkg/errors" "github.com/stretchr/testify/require" + "github.com/wavesplatform/gowaves/pkg/proto" + "github.com/wavesplatform/gowaves/pkg/types" + "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" ) +func Test33(t *testing.T) { + 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") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + thisFunc: func() rideType { + return rideAddress{} + }, + } + for _, test := range []struct { + comment string + source string + env RideEnvironment + res bool + }{ + {`V1: true`, "AQa3b8tH", env, true}, + {`V1: false`, `AQfeYll6`, nil, false}, + {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, + {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", env, true}, + {`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, + {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", env, true}, + {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, + {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, + {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, + {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, + {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, + {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, + {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, + {`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, + {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, + {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, + {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, + {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, + {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, + {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, + {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, + {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, + {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, + {`let x = {let y = true;y}x`, `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C`, nil, true}, + {`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}, + {`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}, + {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, + {`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, + {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, + {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, + {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, + {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, + {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, + {`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}, + } { + src, err := base64.StdEncoding.DecodeString(test.source) + require.NoError(t, err, test.comment) + + tree, err := Parse(src) + require.NoError(t, err, test.comment) + require.NotNil(t, tree, test.comment) + + exe, err := CompileFlatTree(tree) + require.NoError(t, err) + + res, err := exe.Verify(test.env) + require.NoError(t, err, test.comment) + require.NotNil(t, res, test.comment) + + t.Log(res.Calls()) + + r, ok := res.(ScriptResult) + require.True(t, ok, test.comment) + require.Equal(t, test.res, r.Result(), test.comment) + } +} + /* func abc(key: String) = { let x = 1 @@ -143,42 +253,449 @@ func TestReverseFunc2(t *testing.T) { }, rs) } */ + /* -func abc(key: String) = { - let x = 1 - let y = 2 - x + y +func TestReverse2(t *testing.T) { + //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, + source := `BAQAAAABeAYFAAAAAXhUb/5M` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + require.NotNil(t, tree) + + reversed := reverseTree3(tree.Verifier, nil, nil) + require.Equal(t, []RNode{ + &RDef{Name: "x"}, + &RReferenceNode{Name: "x"}, + &RLet{Name: "x"}, + &RConst{Value: rideBoolean(true)}, + }, reversed) + + //env := &MockRideEnvironment{ + // transactionFunc: testExchangeWithProofsToObject, + //} + // + //rs, err := script.Run(env, nil) + //require.NoError(t, err) + //require.Equal(t, 2, len(rs.Calls())) + //require.Equal(t, rs.Result(), true) } */ -func TestReverse2(t *testing.T) { - n := &FunctionDeclarationNode{ - Name: "abc", - Arguments: []string{"key"}, - Body: &AssignmentNode{ - Name: "x", - Expression: &LongNode{Value: 1}, - Block: &AssignmentNode{ - Name: "y", - Expression: &LongNode{Value: 2}, - Block: &FunctionCallNode{ - Name: "+", - Arguments: []Node{ - &ReferenceNode{Name: "x"}, - &ReferenceNode{Name: "y"}, - }, - }, + +/* +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE EXPRESSION #-} + +match (tx) { + case e:ExchangeTransaction => isDefined(e.sellOrder.assetPair.priceAsset) + case _ => throw("err") + } +*/ +func TestMultipleProperty2(t *testing.T) { + source := `AwQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE0V4Y2hhbmdlVHJhbnNhY3Rpb24EAAAAAWUFAAAAByRtYXRjaDAJAQAAAAlpc0RlZmluZWQAAAABCAgIBQAAAAFlAAAACXNlbGxPcmRlcgAAAAlhc3NldFBhaXIAAAAKcHJpY2VBc3NldAkAAAIAAAABAgAAAANlcnIsqB0K` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + require.NotNil(t, tree) + + script, err := CompileFlatTree(tree) + require.NoError(t, err) + require.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + rs, err := script.Verify(env) + require.NoError(t, err) + require.Equal(t, rs.Result(), true) +} + +func TestProperty2(t *testing.T) { + t.Run("test simple property", func(t *testing.T) { + n := &PropertyNode{ + Name: "id", + Object: &ReferenceNode{Name: "tx"}, + } + tree := &Tree{ + LibVersion: 3, + AppVersion: scriptApplicationVersion, + Verifier: n, + } + + script, err := CompileFlatTree(tree) + require.NoError(t, err) + require.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + require.Equal(t, + []byte{ + OpReturn, + OpReturn, + OpRef, 255, 255, + OpRef, 0, 2, + OpProperty, + OpReturn, + }, + script.ByteCode) + _, err = script.run(env, nil) + require.NoError(t, err) + }) + t.Run("test multiple property", func(t *testing.T) { + n := &PropertyNode{ + Name: "assetPair", + Object: &PropertyNode{ + Name: "sellOrder", + Object: &ReferenceNode{Name: "tx"}, + }} + tree := &Tree{ + LibVersion: 3, + AppVersion: scriptApplicationVersion, + Verifier: n, + } + + script, err := CompileFlatTree(tree) + require.NoError(t, err) + require.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + require.Equal(t, + []byte{ + OpReturn, + OpReturn, + OpRef, 255, 255, + OpRef, 0, 2, + OpProperty, + OpRef, 0, 3, + OpProperty, + OpReturn, + }, + script.ByteCode) + _, err = script.run(env, nil) + require.NoError(t, err) + }) +} + +/* +{-# 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 TestDappMultipleFunctions2(t *testing.T) { + source := "AAIDAAAAAAAAAAwIARIDCgEIEgMKAQgAAAAAAAAAAgAAAAFpAQAAAANhYmMAAAABAAAACHF1ZXN0aW9uCQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFhAAAAAAAAAAAFBQAAAANuaWwAAAABaQEAAAADY2JhAAAAAQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQAAAAAAAAAABgUAAAADbmlsAAAAAFEpRso=" + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + require.NotNil(t, tree) + + script, err := CompileFlatTree(tree) + require.NoError(t, err) + require.NotNil(t, script) + + rs, err := script.Invoke(nil, "abc", []rideType{rideString(""), rideString("")}) + require.NoError(t, err) + + require.Equal(t, true, rs.Result()) + require.Equal(t, + []proto.ScriptAction{ + &proto.DataEntryScriptAction{ + Entry: &proto.IntegerDataEntry{Value: 5, Key: "a"}, }, + }, []proto.ScriptAction(rs.ScriptActions())) + + rs, err = script.Invoke(nil, "cba", []rideType{rideString(""), rideString("")}) + require.NoError(t, err) + + require.Equal(t, true, rs.Result()) + require.Equal(t, + []proto.ScriptAction{ + &proto.DataEntryScriptAction{ + Entry: &proto.IntegerDataEntry{Value: 6, Key: "a"}, + }, + }, []proto.ScriptAction(rs.ScriptActions())) +} + +/* +{-# 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 TestIfStmt2(t *testing.T) { + source := `BAoBAAAAAmlkAAAAAQAAAAF2AwUAAAABdgQAAAABeAkAAAIAAAABAgAAAAFhAAAAAAAAAAABBAAAAAF4CQAAAgAAAAECAAAAAWIAAAAAAAAAAAIJAAAAAAAAAgAAAAAAAAAAAQkBAAAAAmlkAAAAAQYYAiEb` + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + script, err := CompileFlatTree(tree) + require.NoError(t, err) + + res, err := script.Verify(env) + require.NoError(t, err) + r, ok := res.(ScriptResult) + require.True(t, ok) + + for _, l := range r.calls { + t.Log(l) + } + + require.Equal(t, true, r.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 TestDapp3(t *testing.T) { + source := `AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==` + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + require.NotNil(t, tree) + + script, err := CompileFlatTree(tree) + require.NoError(t, err) + require.NotNil(t, script) + require.Equal(t, 4, len(script.EntryPoints)) + + rs, err := script.Verify(env) + require.NoError(t, err) + require.NotNil(t, rs) +} + +/* +{-# 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)]) + } + } + +@Verifier(tx) +func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) +*/ +func TestDappVerifier(t *testing.T) { + source := `AAIDAAAAAAAAAAQIARIAAAAAAAAAAAEAAAABaQEAAAAHZGVwb3NpdAAAAAAEAAAAA3BtdAkBAAAAB2V4dHJhY3QAAAABCAUAAAABaQAAAAdwYXltZW50AwkBAAAACWlzRGVmaW5lZAAAAAEIBQAAAANwbXQAAAAHYXNzZXRJZAkAAAIAAAABAgAAACFjYW4gaG9sZCB3YXZlcyBvbmx5IGF0IHRoZSBtb21lbnQEAAAACmN1cnJlbnRLZXkJAAJYAAAAAQgIBQAAAAFpAAAABmNhbGxlcgAAAAVieXRlcwQAAAANY3VycmVudEFtb3VudAQAAAAHJG1hdGNoMAkABBoAAAACBQAAAAR0aGlzBQAAAApjdXJyZW50S2V5AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAAWEFAAAAByRtYXRjaDAFAAAAAWEAAAAAAAAAAAAEAAAACW5ld0Ftb3VudAkAAGQAAAACBQAAAA1jdXJyZW50QW1vdW50CAUAAAADcG10AAAABmFtb3VudAkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwAAAABAAAAAnR4AQAAAAZ2ZXJpZnkAAAAACQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAgFAAAAAnR4AAAAD3NlbmRlclB1YmxpY0tleVRzVhY=` + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil }, } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + require.NotNil(t, tree) + + script, err := CompileFlatTree(tree) + require.NoError(t, err) + require.NotNil(t, script) + + rs, err := script.Verify(env) + require.NoError(t, err) + require.NotNil(t, rs) +} + +func TestLetInLet2(t *testing.T) { + //{`let x = {let y = true;y}x`, `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C`, nil, true}, + source := `AwQAAAABeAQAAAABeQAAAAAAAAAABQYFAAAAAXhy1aZr` + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'T' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + require.NotNil(t, tree) - rs := reverseTree2(n, nil, nil) + script, err := CompileFlatTree(tree) + require.NoError(t, err) + require.NotNil(t, script) + + rs, err := script.Verify(env) + require.NoError(t, err) + require.NotNil(t, rs) +} +func TestFlatProperty(t *testing.T) { + n := &PropertyNode{ + Name: "assetPair", + Object: &PropertyNode{ + Name: "sellOrder", + Object: &ReferenceNode{Name: "tx"}, + }} + rs := flatProperty(n) require.Equal(t, []RNode{ - &RFunc{Invocation: "", Name: "abc", Arguments: []string{"key"}}, - &RRef{Name: "x"}, - &RRef{Name: "y"}, - &RCall{Name: "+"}, - &RLet{Name: "x", Body: []RNode{&RLong{Value: 1}}}, - &RLet{Name: "y", Body: []RNode{&RLong{Value: 2}}}, + &RReferenceNode{Name: "tx"}, + &RConst{Value: rideString("sellOrder")}, + &RProperty{}, + &RConst{Value: rideString("assetPair")}, + &RProperty{}, }, rs) } diff --git a/pkg/ride/reversed_tree.go b/pkg/ride/reversed_tree.go index c2c804bf0a..703819f71e 100644 --- a/pkg/ride/reversed_tree.go +++ b/pkg/ride/reversed_tree.go @@ -5,80 +5,152 @@ type RNode interface { } type RFunc struct { - Invocation string - Name string - Arguments []string - Body RNode + Invocation string + Name string + Arguments []string + ArgumentsWithInvocation []string + Body RNode } func (a *RFunc) RNode() {} type RLet struct { Name string - //N uniqueid - Body []RNode } func (a *RLet) RNode() {} +type RRet struct { +} + +func (a *RRet) RNode() {} + type RCond struct { - Cond RNode - True RNode - False RNode - Assigments []*RLet } func (a *RCond) RNode() {} +type RCondEnd struct { +} + +func (a *RCondEnd) RNode() {} + +type RCondTrue struct { +} + +func (a *RCondTrue) RNode() {} + +type RCondFalse struct { +} + +func (a *RCondFalse) RNode() {} + +type RFuncEnd struct { +} + +func (a *RFuncEnd) RNode() {} + +//type RCond struct { +// Cond RNode +// True RNode +// False RNode +// Assigments []*RLet +//} +// +//func (a *RCond) RNode() {} + type RCall struct { - Name string - Arguments []RNode - Assigments []*RLet - Next RNode + Name string + //Arguments []RNode + Argn uint16 + //Assigments []*RLet + //Next RNode } func (a *RCall) RNode() {} -func reverseRnodes(a []RNode) []RNode { - out := make([]RNode, len(a)) - for i := 0; i < len(a); i++ { - out[len(a)-1-i] = a[i] - } - return out +//func reverseRnodes(a []RNode) []RNode { +// out := make([]RNode, len(a)) +// for i := 0; i < len(a); i++ { +// out[len(a)-1-i] = a[i] +// } +// return out +//} + +//func (a *RCall) CallTree() []RNode { +// d := []RNode{ +// a, +// } +// for i := len(a.Arguments) - 1; i >= 0; i-- { +// switch t := a.Arguments[i].(type) { +// case *RConst: +// d = append(d, a.Arguments[i]) +// case *RCall: +// d = append(d, t.CallTree()...) +// default: +// panic("") +// } +// } +// return d +//} + +// +//type RRef struct { +// Name string +// Assigments []*RLet +//} +// +//func (a *RRef) RNode() {} + +//type RLong struct { +// Value int64 +//} +// +//func (a *RLong) RNode() {} + +type RConst struct { + Value rideType } -func (a *RCall) CallTree() []RNode { - d := []RNode{ - a, - } - for i := len(a.Arguments) - 1; i >= 0; i-- { - switch t := a.Arguments[i].(type) { - case *RLong: - d = append(d, a.Arguments[i]) - case *RCall: - d = append(d, t.CallTree()...) - default: - panic("") - } - } - return d +func (a *RConst) RNode() {} + +type RProperty struct{} + +func (a *RProperty) RNode() {} + +//type RString struct { +// Value string +//} +// +//func (a *RString) RNode() {} + +//type RBoolean struct { +// Value bool +//} +// +//func (a *RBoolean) RNode() {} + +type RReferenceNode struct { + Name string } -type RRef struct { - Name string - Assigments []*RLet +func (a *RReferenceNode) RNode() {} + +type RStart struct { + Name string } -func (a *RRef) RNode() {} +func (a *RStart) RNode() {} -type RLong struct { - Value int64 +type RDef struct { + Name string + Arguments []string } -func (a *RLong) RNode() {} +func (a *RDef) RNode() {} -type RString struct { - Value string +type RBody struct { + Name string } -func (a *RString) RNode() {} +func (a *RBody) RNode() {} diff --git a/pkg/ride/runtime.go b/pkg/ride/runtime.go index 0bb761e8c2..d1af48e947 100644 --- a/pkg/ride/runtime.go +++ b/pkg/ride/runtime.go @@ -14,10 +14,15 @@ type rideType interface { instanceOf() string eq(other rideType) bool get(prop string) (rideType, error) + Serialize(Serializer) error } type rideThrow string +func (a rideThrow) Serialize(serializer Serializer) error { + panic("implement me") +} + func (a rideThrow) instanceOf() string { return "Throw" } @@ -40,6 +45,10 @@ func (a rideThrow) get(prop string) (rideType, error) { type rideBoolean bool +func (b rideBoolean) Serialize(serializer Serializer) error { + return serializer.RideBool(b) +} + func (b rideBoolean) instanceOf() string { return "Boolean" } @@ -57,6 +66,10 @@ func (b rideBoolean) get(prop string) (rideType, error) { type rideInt int64 +func (l rideInt) Serialize(serializer Serializer) error { + return serializer.RideInt(l) +} + func (l rideInt) instanceOf() string { return "Int" } @@ -74,6 +87,10 @@ func (l rideInt) get(prop string) (rideType, error) { type rideString string +func (s rideString) Serialize(serializer Serializer) error { + return serializer.RideString(s) +} + func (s rideString) instanceOf() string { return "String" } @@ -91,6 +108,10 @@ func (s rideString) get(prop string) (rideType, error) { type rideBytes []byte +func (b rideBytes) Serialize(serializer Serializer) error { + return serializer.RideBytes(b) +} + func (b rideBytes) instanceOf() string { return "ByteVector" } @@ -108,6 +129,10 @@ func (b rideBytes) get(prop string) (rideType, error) { type rideObject map[string]rideType +func (o rideObject) Serialize(Serializer) error { + panic("implement me") +} + func (o rideObject) instanceOf() string { if s, ok := o[instanceFieldName].(rideString); ok { return string(s) @@ -141,6 +166,10 @@ func (o rideObject) get(prop string) (rideType, error) { type rideAddress proto.Address +func (a rideAddress) Serialize(Serializer) error { + panic("implement me") +} + func (a rideAddress) instanceOf() string { return "Address" } @@ -169,6 +198,10 @@ func (a rideAddress) get(prop string) (rideType, error) { type rideAddressLike []byte +func (a rideAddressLike) Serialize(serializer Serializer) error { + panic("implement me") +} + func (a rideAddressLike) instanceOf() string { return "Address" } @@ -197,6 +230,10 @@ func (a rideAddressLike) get(prop string) (rideType, error) { type rideRecipient proto.Recipient +func (a rideRecipient) Serialize(serializer Serializer) error { + panic("rideRecipient Serialize implement me") +} + func (a rideRecipient) instanceOf() string { switch { case a.Address != nil: @@ -247,6 +284,10 @@ func (a rideRecipient) String() string { type rideAlias proto.Alias +func (a rideAlias) Serialize(Serializer) error { + panic("implement me") +} + func (a rideAlias) instanceOf() string { return "Alias" } @@ -273,6 +314,10 @@ func (a rideAlias) get(prop string) (rideType, error) { type rideUnit struct{} +func (a rideUnit) Serialize(Serializer) error { + panic("rideUnit Serialize: implement me") +} + func (a rideUnit) instanceOf() string { return "Unit" } @@ -289,6 +334,10 @@ type rideNamedType struct { name string } +func (a rideNamedType) Serialize(serializer Serializer) error { + panic("rideNamedType Serialize: implement me") +} + func (a rideNamedType) instanceOf() string { return a.name } @@ -303,6 +352,10 @@ func (a rideNamedType) get(prop string) (rideType, error) { type rideList []rideType +func (a rideList) Serialize(Serializer) error { + panic("implement me") +} + func (a rideList) instanceOf() string { return "List[Any]" } diff --git a/pkg/ride/serializer.go b/pkg/ride/serializer.go index 09f652a737..9af34515dd 100644 --- a/pkg/ride/serializer.go +++ b/pkg/ride/serializer.go @@ -3,48 +3,131 @@ package ride import ( "bytes" "encoding/binary" + "math" + + "github.com/pkg/errors" ) const ( - s0 byte = iota - s1 - s2 - s3 - s4 - s5 - s6 - s7 - s8 - s9 - strue - sfalse - sint - suint16 - sbytes - sstring - spoint + strue byte = 101 + sfalse = 102 + sint = 103 + suint16 = 104 + sbytes = 105 + sString = 106 + spoint = 107 + sMap = 108 + sNoValue = 109 ) type Serializer struct { - b bytes.Buffer + b *bytes.Buffer +} + +func NewSerializer() Serializer { + return Serializer{b: &bytes.Buffer{}} } -func (a *Serializer) Int(v rideInt) { - if v >= 0 && v <= 9 { +func (a *Serializer) RideInt(v rideInt) error { + if v >= 0 && v <= 100 { a.b.WriteByte(byte(v)) - return + return nil } a.b.WriteByte(sint) b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) a.b.Write(b) + return nil +} + +func (a *Serializer) RideNoValue() error { + return a.b.WriteByte(sNoValue) +} + +func (a *Serializer) Tuple(values ...rideType) error { + panic("not implemented") } func (a *Serializer) Uint16(v uint16) { - a.Int(rideInt(v)) + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, v) + a.b.Write(b) +} + +func (a *Serializer) Bool(v bool) { + if v { + a.b.WriteByte(strue) + } else { + a.b.WriteByte(sfalse) + } } func (a *Serializer) Point(p point) { a.b.WriteByte(spoint) a.Uint16(p.position) } + +func (a *Serializer) Byte(b byte) { + a.b.WriteByte(b) +} + +func (a *Serializer) RideBytes(v rideBytes) error { + a.b.WriteByte(sbytes) + return a.Bytes(v) +} + +func (a *Serializer) Bytes(v []byte) error { + if len(v) > math.MaxUint16 { + return errors.New("bytes length overflow") + } + a.Uint16(uint16(len(v))) + a.b.Write(v) + return nil +} + +func (a *Serializer) Source() []byte { + return a.b.Bytes() +} + +func (a *Serializer) RideMap(size int) error { + a.b.WriteByte(sMap) + if size > math.MaxUint16 { + return errors.New("size overflow") + } + a.Uint16(uint16(size)) + return nil +} + +func (a *Serializer) RideString(v rideString) error { + a.b.WriteByte(sString) + return a.String(v) +} + +func (a *Serializer) String(v rideString) error { + if len(v) > math.MaxUint16 { + return errors.New("bytes length overflow") + } + a.Uint16(uint16(len(v))) + a.b.Write([]byte(v)) + return nil +} + +func (a Serializer) RideBool(v rideBoolean) error { + a.Bool(bool(v)) + return nil +} + +func (a *Serializer) Map(size int, f func(Map) error) error { + err := a.RideMap(size) + if err != nil { + return err + } + return f(a) +} + +type Map interface { + Uint16(v uint16) + RideInt(v rideInt) error + RideBytes(v rideBytes) error + RideString(v rideString) error +} diff --git a/pkg/ride/tree.go b/pkg/ride/tree.go index b270af1fa3..e24ee832d9 100644 --- a/pkg/ride/tree.go +++ b/pkg/ride/tree.go @@ -131,6 +131,10 @@ type FunctionCallNode struct { Arguments []Node } +func (a *FunctionCallNode) ArgumentsCount() uint16 { + return uint16(len(a.Arguments)) +} + func (*FunctionCallNode) node() {} func (*FunctionCallNode) SetBlock(Node) {} diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 358ba1ef1f..dcc003e615 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -13,28 +13,24 @@ func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { return e.evaluate() } -func CallVmVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { - compiled, err := CompileVerifier(txID, tree) - if err != nil { - return nil, errors.Wrap(err, "call compile script") - } +func CallVmVerifier(txID string, env RideEnvironment, compiled *Executable) (RideResult, error) { if env == nil { return nil, errors.Errorf("env is nil") } - return compiled.Run(env, []rideType{env.transaction()}) + return compiled.Verify(env) } func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { - r, err := CallVmVerifier(txID, env, tree) + //r, err := CallVmVerifier(txID, env, tree) + //if err != nil { + // return nil, err + //} + + r2, err := CallTreeVerifier(env, tree) if err != nil { return nil, err } - /* - r2, err := CallTreeVerifier(env, tree) - if err != nil { - return nil, err - } if !r.Eq(r2) { c1 := r.Calls() c2 := r2.Calls() @@ -59,7 +55,7 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, err return nil, errors.New("R1 != R2: failed to call account script on transaction ") } */ - return r, nil + return r2, nil } func CallTreeFunction(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { @@ -74,32 +70,37 @@ func CallTreeFunction(env RideEnvironment, tree *Tree, name string, args proto.A } func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - //rs1, err := CallTreeFunction(env, tree, name, args) - //if err != nil { - // return nil, errors.Wrap(err, "call function by tree") - //} - rs2, err := CallFunction2(txID, env, tree, name, args) - if err != nil { - return rs2, errors.Wrap(err, "call function by vm") - } - //if !rs1.Eq(rs2) { - // zap.S().Errorf("%s, result mismatch", txID) - // zap.S().Errorf("tree: %+q", rs1) - // zap.S().Errorf("vm : %+q", rs2) - // return nil, errors.New(txID + ": result mismatch") - //} - return rs2, nil + return CallTreeFunction(env, tree, name, args) } -func CallFunction2(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { +//func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { +// +// //rs1, err := CallTreeFunction(env, tree, name, args) +// //if err != nil { +// // return nil, errors.Wrap(err, "call function by tree") +// //} +// rs2, err := CallVmFunction(txID, env, tree, name, args) +// if err != nil { +// return rs2, errors.Wrap(err, "call function by vm") +// } +// //if !rs1.Eq(rs2) { +// // zap.S().Errorf("%s, result mismatch", txID) +// // zap.S().Errorf("tree: %+q", rs1) +// // zap.S().Errorf("vm : %+q", rs2) +// // return nil, errors.New(txID + ": result mismatch") +// //} +// return rs2, nil +//} + +func CallVmFunction(txID string, env RideEnvironment, e *Executable, name string, args proto.Arguments) (RideResult, error) { if name == "" { name = "default" } - f, numArgs, err := CompileFunction(txID, tree, name, args, tree.IsDApp()) + entry, err := e.Entrypoint(name) if err != nil { return nil, err } - if l := len(args); l != numArgs { + if l := len(args); l != int(entry.argn) { return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) } applyArgs := make([]rideType, 0, len(args)+1) @@ -109,12 +110,7 @@ func CallFunction2(txID string, env RideEnvironment, tree *Tree, name string, ar if err != nil { return nil, errors.Wrapf(err, "failed to call function '%s'", name) } - //s.pushValue(function.Arguments[i], a) applyArgs = append(applyArgs, a) - //namedArgument{ - // name: function.Arguments[i], - // arg: a, - //}) } - return f.Run(env, applyArgs) + return e.Invoke(env, name, applyArgs) } diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 4839fdd1b1..8b7a9ff527 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -443,7 +443,7 @@ func TestDataFunctions(t *testing.T) { require.NoError(t, err, test.name) assert.NotNil(t, tree, test.name) - res, err := CallVerifier("", env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err, test.name) r, ok := res.(ScriptResult) require.True(t, ok, test.name) @@ -515,7 +515,7 @@ func TestDappCallable(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "tellme", proto.Arguments{proto.NewStringArgument("abc")}) + res, err := CallTreeFunction(env, tree, "tellme", proto.Arguments{proto.NewStringArgument("abc")}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -853,7 +853,7 @@ func TestMatchOverwrite(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -912,7 +912,7 @@ func TestFailSript1(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -1024,7 +1024,7 @@ func TestFailSript2(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -1139,7 +1139,7 @@ func TestWhaleDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "inviteuser", arguments) + res, err := CallTreeFunction(env, tree, "inviteuser", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1432,7 +1432,7 @@ func TestBankDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "buyBack", proto.Arguments{}) + res, err := CallTreeFunction(env, tree, "buyBack", proto.Arguments{}) require.NoError(t, err) _, ok := res.(DAppResult) require.True(t, ok) diff --git a/pkg/ride/tuples.go b/pkg/ride/tuples.go index 5881bdf62e..2a563cdca3 100644 --- a/pkg/ride/tuples.go +++ b/pkg/ride/tuples.go @@ -57,6 +57,10 @@ func (a tuple2) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) } +func (a tuple2) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2) +} + type tuple3 struct { el1 rideType el2 rideType @@ -109,6 +113,10 @@ func (a tuple3) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) } +func (a tuple3) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3) +} + type tuple4 struct { el1 rideType el2 rideType @@ -165,6 +173,10 @@ func (a tuple4) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) } +func (a tuple4) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4) +} + type tuple5 struct { el1 rideType el2 rideType @@ -225,6 +237,10 @@ func (a tuple5) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) } +func (a tuple5) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5) +} + type tuple6 struct { el1 rideType el2 rideType @@ -289,6 +305,10 @@ func (a tuple6) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) } +func (a tuple6) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6) +} + type tuple7 struct { el1 rideType el2 rideType @@ -357,6 +377,10 @@ func (a tuple7) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) } +func (a tuple7) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7) +} + type tuple8 struct { el1 rideType el2 rideType @@ -429,6 +453,10 @@ func (a tuple8) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) } +func (a tuple8) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8) +} + type tuple9 struct { el1 rideType el2 rideType @@ -505,6 +533,10 @@ func (a tuple9) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) } +func (a tuple9) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9) +} + type tuple10 struct { el1 rideType el2 rideType @@ -585,6 +617,10 @@ func (a tuple10) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) } +func (a tuple10) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10) +} + type tuple11 struct { el1 rideType el2 rideType @@ -669,6 +705,10 @@ func (a tuple11) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) } +func (a tuple11) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11) +} + type tuple12 struct { el1 rideType el2 rideType @@ -757,6 +797,10 @@ func (a tuple12) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) } +func (a tuple12) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12) +} + type tuple13 struct { el1 rideType el2 rideType @@ -849,6 +893,10 @@ func (a tuple13) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) } +func (a tuple13) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13) +} + type tuple14 struct { el1 rideType el2 rideType @@ -945,6 +993,10 @@ func (a tuple14) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) } +func (a tuple14) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14) +} + type tuple15 struct { el1 rideType el2 rideType @@ -1045,6 +1097,10 @@ func (a tuple15) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) } +func (a tuple15) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15) +} + type tuple16 struct { el1 rideType el2 rideType @@ -1149,6 +1205,10 @@ func (a tuple16) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) && a.el16.eq(o.el16) } +func (a tuple16) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15, a.el16) +} + type tuple17 struct { el1 rideType el2 rideType @@ -1257,6 +1317,10 @@ func (a tuple17) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) && a.el16.eq(o.el16) && a.el17.eq(o.el17) } +func (a tuple17) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15, a.el16, a.el17) +} + type tuple18 struct { el1 rideType el2 rideType @@ -1369,6 +1433,10 @@ func (a tuple18) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) && a.el16.eq(o.el16) && a.el17.eq(o.el17) && a.el18.eq(o.el18) } +func (a tuple18) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15, a.el16, a.el17, a.el18) +} + type tuple19 struct { el1 rideType el2 rideType @@ -1485,6 +1553,10 @@ func (a tuple19) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) && a.el16.eq(o.el16) && a.el17.eq(o.el17) && a.el18.eq(o.el18) && a.el19.eq(o.el19) } +func (a tuple19) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15, a.el16, a.el17, a.el18, a.el19) +} + type tuple20 struct { el1 rideType el2 rideType @@ -1605,6 +1677,10 @@ func (a tuple20) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) && a.el16.eq(o.el16) && a.el17.eq(o.el17) && a.el18.eq(o.el18) && a.el19.eq(o.el19) && a.el20.eq(o.el20) } +func (a tuple20) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15, a.el16, a.el17, a.el18, a.el19, a.el20) +} + type tuple21 struct { el1 rideType el2 rideType @@ -1729,6 +1805,10 @@ func (a tuple21) eq(other rideType) bool { return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) && a.el16.eq(o.el16) && a.el17.eq(o.el17) && a.el18.eq(o.el18) && a.el19.eq(o.el19) && a.el20.eq(o.el20) && a.el21.eq(o.el21) } +func (a tuple21) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15, a.el16, a.el17, a.el18, a.el19, a.el20, a.el21) +} + type tuple22 struct { el1 rideType el2 rideType @@ -1856,3 +1936,7 @@ func (a tuple22) eq(other rideType) bool { } return a.el1.eq(o.el1) && a.el2.eq(o.el2) && a.el3.eq(o.el3) && a.el4.eq(o.el4) && a.el5.eq(o.el5) && a.el6.eq(o.el6) && a.el7.eq(o.el7) && a.el8.eq(o.el8) && a.el9.eq(o.el9) && a.el10.eq(o.el10) && a.el11.eq(o.el11) && a.el12.eq(o.el12) && a.el13.eq(o.el13) && a.el14.eq(o.el14) && a.el15.eq(o.el15) && a.el16.eq(o.el16) && a.el17.eq(o.el17) && a.el18.eq(o.el18) && a.el19.eq(o.el19) && a.el20.eq(o.el20) && a.el21.eq(o.el21) && a.el22.eq(o.el22) } + +func (a tuple22) Serialize(serializer Serializer) error { + return serializer.Tuple(a.el1, a.el2, a.el3, a.el4, a.el5, a.el6, a.el7, a.el8, a.el9, a.el10, a.el11, a.el12, a.el13, a.el14, a.el15, a.el16, a.el17, a.el18, a.el19, a.el20, a.el21, a.el22) +} diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index d7997d3a54..ad84d3eea0 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -6,28 +6,21 @@ import ( "github.com/pkg/errors" ) -const limitOperations = 50000 - -var throwErr = errors.New("throw") +const limitOperations = 200000 type vm struct { env RideEnvironment code []byte ip int - functions func(int) rideFunction stack []rideType - functionName func(int) string jmps []int ref map[uint16]point calls []callLog numOperations int + libVersion int } func (m *vm) run() (rideType, error) { - //if m.stack != nil { - // m.stack = m.stack[0:0] - //} - for m.ip < len(m.code) { if m.numOperations >= limitOperations { return nil, errors.New("limit operations exceed") @@ -67,8 +60,6 @@ func (m *vm) run() (rideType, error) { m.ip = posFalse } case OpProperty: - - //n := m.uint16() prop, err := m.pop() if err != nil { return nil, err //errors.Wrap(err, "no ref %d", n) @@ -99,17 +90,25 @@ func (m *vm) run() (rideType, error) { for i := cnt - 1; i >= 0; i-- { v, err := m.pop() if err != nil { - return nil, errors.Wrapf(err, "failed to call external function '%s'", m.functionName(id)) + return nil, errors.Wrap(err, "failed to call external function") } in[i] = v } - fn := m.functions(id) + functions, err := selectFunctions(m.libVersion) + if err != nil { + return nil, err + } + provider, err := selectFunctionNameProvider(m.libVersion) + if err != nil { + return nil, err + } + fn := functions(id) if fn == nil { - return nil, errors.Errorf("external function '%s' not implemented", m.functionName(id)) + return nil, errors.Errorf("external function '%s' not implemented", provider(id)) } res, err := fn(m.env, in...) m.calls = append(m.calls, callLog{ - name: m.functionName(id), + name: provider(id), args: in, result: res, }) @@ -118,7 +117,6 @@ func (m *vm) run() (rideType, error) { } if isThrow(res) { return res, nil - //return nil, errors.Wrapf(throwErr, "terminated execution by throw with message %q on iteration %d", res, m.numOperations) } m.push(res) case OpReturn: @@ -159,7 +157,7 @@ func (m *vm) run() (rideType, error) { return nil, errors.Errorf("OpClearCache: no ref with id %d", refID) } // Clear cache only if its not constant. - if !point.constant { + if !point.constant() { point.value = nil m.ref[refID] = point } diff --git a/pkg/state/invoke_applier.go b/pkg/state/invoke_applier.go index cf67a2a2d6..ec06792078 100644 --- a/pkg/state/invoke_applier.go +++ b/pkg/state/invoke_applier.go @@ -522,6 +522,11 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf if err != nil { return nil, errors.Wrap(err, "recipientToAddress() failed") } + //tree, err := ia.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !info.initialisation) + exe, err := ia.stor.scriptsStorage.newestBytecodeByAddr(*scriptAddr, !info.initialisation) + if err != nil { + return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) + } tree, err := ia.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !info.initialisation) if err != nil { return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) @@ -532,11 +537,11 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf } // Check that the script's library supports multiple payments. // We don't have to check feature activation because we done it before. - if len(tx.Payments) == 2 && tree.LibVersion < 4 { - return nil, errors.Errorf("multiple payments is not allowed for RIDE library version %d", tree.LibVersion) + if len(tx.Payments) == 2 && exe.LibVersion < 4 { + return nil, errors.Errorf("multiple payments is not allowed for RIDE library version %d", exe.LibVersion) } // Refuse payments to DApp itself since activation of BlockV5 (acceptFailed) and for DApps with StdLib V4. - disableSelfTransfers := info.acceptFailed && tree.LibVersion >= 4 + disableSelfTransfers := info.acceptFailed && exe.LibVersion >= 4 if disableSelfTransfers && len(tx.Payments) > 0 { sender, err := proto.NewAddressFromPublicKey(ia.settings.AddressSchemeCharacter, tx.SenderPK) if err != nil { @@ -554,7 +559,7 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf return nil, err } // Call script function. - ok, scriptActions, err := ia.sc.invokeFunction(tree, tx, info.blockInfo, *scriptAddr, info.initialisation) + ok, scriptActions, err := ia.sc.invokeFunction(exe, tx, info.blockInfo, *scriptAddr, info.initialisation, tree) if !ok { // When ok is false, it means that we could not even start invocation. // We just return error in such case. @@ -583,7 +588,7 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf actions: scriptActions, paymentSmartAssets: paymentSmartAssets, disableSelfTransfers: disableSelfTransfers, - libVersion: byte(tree.LibVersion), + libVersion: byte(exe.LibVersion), }) if err != nil { // If fallibleValidation fails, we should save transaction to blockchain when acceptFailed is true. diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index 4245e01d1e..facec89318 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -43,7 +43,8 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return err } - tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) + //tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) + tree, err := a.stor.scriptsStorage.newestBytecodeByAddr(sender, !initialisation) if err != nil { return errors.Wrap(err, "failed to retrieve account script") } @@ -58,7 +59,7 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return errors.Wrap(err, "failed to convert order") } - r, err := ride.CallVerifier("scriptCaller callAccountScriptWithOrder", env, tree) + r, err := ride.CallVmVerifier("scriptCaller callAccountScriptWithOrder", env, tree) if err != nil { return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) } @@ -91,11 +92,11 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return err } - tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) + tree, err := a.stor.scriptsStorage.newestBytecodeByAddr(senderAddr, !initialisation) + //tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) if err != nil { return err } - //zap.S().Error(ride.Decompiler(tree.Verifier)) env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) if err != nil { @@ -108,7 +109,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } //zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) - r, err := ride.CallVerifier(txID, env, tree) + r, err := ride.CallVmVerifier(txID, env, tree) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } @@ -141,7 +142,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn } func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID crypto.Digest, lastBlockInfo *proto.BlockInfo, initialisation bool, acceptFailed bool) (ride.RideResult, error) { - tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !initialisation) + tree, err := a.stor.scriptsStorage.newestBytecodeByAsset(assetID, !initialisation) if err != nil { return nil, err } @@ -161,7 +162,7 @@ func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID cryp env.SetThisFromAssetInfo(assetInfo) } env.SetLastBlock(lastBlockInfo) - r, err := ride.CallVerifier("scriptCaller callAssetScriptCommon", env, tree) + r, err := ride.CallVmVerifier("scriptCaller callAssetScriptCommon", env, tree) if err != nil { return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) } @@ -202,7 +203,7 @@ func (a *scriptCaller) callAssetScript(tx proto.Transaction, assetID crypto.Dige return a.callAssetScriptCommon(env, assetID, lastBlockInfo, initialisation, acceptFailed) } -func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWithProofs, lastBlockInfo *proto.BlockInfo, scriptAddress proto.Address, initialisation bool) (bool, []proto.ScriptAction, error) { +func (a *scriptCaller) invokeFunction(exe *ride.Executable, tx *proto.InvokeScriptWithProofs, lastBlockInfo *proto.BlockInfo, scriptAddress proto.Address, initialisation bool, tree *ride.Tree) (bool, []proto.ScriptAction, error) { txID := tx.ID.String() _ = txID env, err := ride.NewEnvironment(a.settings.AddressSchemeCharacter, a.state) @@ -219,17 +220,25 @@ func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx *proto.InvokeScriptWit if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } - env.ChooseSizeCheck(tree.LibVersion) + env.ChooseSizeCheck(exe.LibVersion) - for i, f := range tree.Functions { + for i, f := range tree.Declarations { rs := ride.Decompiler(f) zap.S().Error(i, " == ", rs) } + for i, f := range tree.Functions { + rs := ride.Decompiler(f) + zap.S().Error(i, " == ", rs) + } - //zap.S().Error(ride.Decompiler(tree.)) + zap.S().Error("verifier: == ", tree.Verifier) + for i, v := range tx.FunctionCall.Arguments { + zap.S().Errorf("%d argument %+v, %T", i, v, v) + } - r, err := ride.CallFunction(txID, env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + r, err := ride.CallVmFunction(txID, env, exe, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + //r, err := ride.CallFunction(txID, env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } diff --git a/pkg/state/scripts_cache.go b/pkg/state/scripts_cache.go index 2219b517fd..77858d317e 100644 --- a/pkg/state/scripts_cache.go +++ b/pkg/state/scripts_cache.go @@ -7,13 +7,11 @@ import ( type element struct { key string - value ride.Tree + value *ride.Executable prev, next *element bytes uint64 } -var defaultValue ride.Tree - type lru struct { maxSize, maxBytes, size, bytesUsed uint64 @@ -72,7 +70,7 @@ func (l *lru) del(e *element) { l.cut(e) l.size -= 1 l.bytesUsed -= e.bytes - e.value = defaultValue + e.value = nil l.removed = e } @@ -82,18 +80,20 @@ func (l *lru) makeFreeSpace(bytes uint64) { } } -func (l *lru) get(key []byte) (value ride.Tree, has bool) { +func (l *lru) get(key []byte) (value *ride.Executable, has bool) { var e *element e, has = l.m[string(key)] if !has { return } + panic("unreachable!!") l.cut(e) l.setNewest(e) return e.value, true } -func (l *lru) set(key []byte, value ride.Tree, bytes uint64) (existed bool) { +func (l *lru) set(key []byte, value *ride.Executable, bytes uint64) (existed bool) { + return false keyStr := string(key) e, has := l.m[keyStr] if has { diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 49b382208f..2491eb60a4 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -2,12 +2,14 @@ package state import ( "bytes" - "errors" + "encoding/binary" "io" "github.com/wavesplatform/gowaves/pkg/crypto" + "github.com/wavesplatform/gowaves/pkg/libs/deserializer" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/ride" + "go.uber.org/zap" ) const ( @@ -18,11 +20,35 @@ const ( ) func scriptBytesToTree(script proto.Script) (*ride.Tree, error) { - tree, err := ride.Parse(script) + + if len(script) == 0 { + panic("scriptBytesToTree") + } + zap.S().Debug("scriptBytesToTree scrip %v, len %d", script, len(script)) + + return ride.Parse(script) +} + +func scriptBytesToVmBytes(script proto.Script) ([]byte, error) { + panic("unreachable") + p, err := scriptBytesToTree(script) if err != nil { return nil, err } - return tree, nil + exe, err := ride.CompileTree("performSetScriptWithProofs", p) + if err != nil { + return nil, err + } + s := ride.NewSerializer() + err = exe.Serialize(s) + if err != nil { + return nil, err + } + return s.Source(), nil +} + +func scriptBytesToExecutable(script proto.Script) (*ride.Executable, error) { + return ride.DeserializeExecutable(script) } type accountScripRecordForHashes struct { @@ -75,8 +101,9 @@ func scriptExists(recordBytes []byte) bool { } type scriptRecord struct { - pk crypto.PublicKey - script proto.Script + pk crypto.PublicKey + script proto.Script + bytecode []byte } func (r *scriptRecord) scriptIsEmpty() bool { @@ -84,25 +111,43 @@ func (r *scriptRecord) scriptIsEmpty() bool { } func (r *scriptRecord) marshalBinary() ([]byte, error) { - res := make([]byte, crypto.KeySize+len(r.script)) - copy(res, r.pk[:]) - copy(res[crypto.KeySize:], r.script) - return res, nil + if len(r.script) > 0 { + res := make([]byte, crypto.KeySize+len(r.script)+len(r.bytecode)+4) + copy(res, r.pk[:]) + binary.BigEndian.PutUint32(res[crypto.KeySize:], uint32(len(r.script))) + copy(res[crypto.KeySize+4:], append(r.script, r.bytecode...)) + return res, nil + } else { + return r.pk.Bytes(), nil + } } func (r *scriptRecord) unmarshalBinary(data []byte) error { - if len(data) < crypto.KeySize { - return errors.New("insufficient data for scriptRecord") + var err error + d := deserializer.NewDeserializer(data) + r.pk, err = d.PublicKey() + if err != nil { + return err } - pk, err := crypto.NewPublicKeyFromBytes(data[:crypto.KeySize]) + if d.Len() == 0 { + return nil + } + size, err := d.Uint32() if err != nil { return err } - r.pk = pk - scriptBytes := make([]byte, len(data)-crypto.KeySize) - copy(scriptBytes, data[crypto.KeySize:]) - r.script = proto.Script(scriptBytes) - return nil + r.script, err = d.Bytes(uint(size)) + if err != nil { + return err + } + r.bytecode, err = d.Bytes(uint(d.Len())) + return err + //scriptBytes := make([]byte, size) + //copy(scriptBytes, data[crypto.KeySize:]) + //r.script = scriptBytes + //data = data[size:] + //r.bytecode = common.Dup(data) + //return nil } // TODO: LRU cache for script ASTs here only makes sense at the import stage. @@ -135,7 +180,26 @@ func newScriptsStorage(hs *historyStorage, calcHashes bool) (*scriptsStorage, er }, nil } -func (ss *scriptsStorage) setScript(scriptType blockchainEntity, key []byte, record scriptRecord, blockID proto.BlockID) error { +func (ss *scriptsStorage) setScript(scriptType blockchainEntity, key []byte, record scriptRecord, blockID proto.BlockID, txID string) error { + var exe *ride.Executable + if len(record.script) > 0 { + if len(record.bytecode) == 0 { + p, err := scriptBytesToTree(record.script) + if err != nil { + return err + } + exe, err = ride.CompileTree("scriptsStorage setScript "+txID, p) + if err != nil { + return err + } + s := ride.NewSerializer() + err = exe.Serialize(s) + if err != nil { + return err + } + record.bytecode = s.Source() + } + } recordBytes, err := record.marshalBinary() if err != nil { return err @@ -148,11 +212,15 @@ func (ss *scriptsStorage) setScript(scriptType blockchainEntity, key []byte, rec ss.cache.deleteIfExists(key) return nil } - tree, err := scriptBytesToTree(record.script) - if err != nil { - return err + if exe == nil { + exe, err := scriptBytesToExecutable(record.script) + if err != nil { + return err + } + ss.cache.set(key, exe, scriptSize) + } else { + ss.cache.set(key, exe, scriptSize) } - ss.cache.set(key, *tree, scriptSize) return nil } @@ -193,6 +261,19 @@ func (ss *scriptsStorage) scriptAstFromRecordBytes(recordBytes []byte) (*ride.Tr return tree, record.pk, err } +func (ss *scriptsStorage) scriptExecutableFromRecordBytes(recordBytes []byte) (*ride.Executable, crypto.PublicKey, error) { + var record scriptRecord + if err := record.unmarshalBinary(recordBytes); err != nil { + return nil, crypto.PublicKey{}, err + } + if record.scriptIsEmpty() { + // Empty script = no script. + return nil, crypto.PublicKey{}, proto.ErrNotFound + } + tree, err := scriptBytesToExecutable(record.bytecode) + return tree, record.pk, err +} + func (ss *scriptsStorage) newestScriptAstByKey(key []byte, filter bool) (*ride.Tree, error) { recordBytes, err := ss.hs.newestTopEntryData(key, filter) if err != nil { @@ -202,6 +283,15 @@ func (ss *scriptsStorage) newestScriptAstByKey(key []byte, filter bool) (*ride.T return tree, err } +func (ss *scriptsStorage) newestBytecodeByKey(key []byte, filter bool) (*ride.Executable, error) { + recordBytes, err := ss.hs.newestTopEntryData(key, filter) + if err != nil { + return nil, err + } + tree, _, err := ss.scriptExecutableFromRecordBytes(recordBytes) + return tree, err +} + func (ss *scriptsStorage) scriptTreeByKey(key []byte, filter bool) (*ride.Tree, error) { recordBytes, err := ss.hs.topEntryData(key, filter) if err != nil { @@ -213,7 +303,7 @@ func (ss *scriptsStorage) scriptTreeByKey(key []byte, filter bool) (*ride.Tree, func (ss *scriptsStorage) commitUncertain(blockID proto.BlockID) error { for assetID, r := range ss.uncertainAssetScripts { - if err := ss.setAssetScript(assetID, r.script, r.pk, blockID); err != nil { + if err := ss.setAssetScript(assetID, r.script, r.pk, blockID, "commitUncertain"); err != nil { return err } } @@ -228,7 +318,7 @@ func (ss *scriptsStorage) setAssetScriptUncertain(assetID crypto.Digest, script ss.uncertainAssetScripts[assetID] = scriptRecord{pk: pk, script: script} } -func (ss *scriptsStorage) setAssetScript(assetID crypto.Digest, script proto.Script, pk crypto.PublicKey, blockID proto.BlockID) error { +func (ss *scriptsStorage) setAssetScript(assetID crypto.Digest, script proto.Script, pk crypto.PublicKey, blockID proto.BlockID, txID string) error { key := assetScriptKey{assetID} keyBytes := key.bytes() keyStr := string(keyBytes) @@ -242,7 +332,7 @@ func (ss *scriptsStorage) setAssetScript(assetID crypto.Digest, script proto.Scr return err } } - return ss.setScript(assetScript, keyBytes, record, blockID) + return ss.setScript(assetScript, keyBytes, record, blockID, txID) } func (ss *scriptsStorage) newestIsSmartAsset(assetID crypto.Digest, filter bool) bool { @@ -279,17 +369,37 @@ func (ss *scriptsStorage) newestScriptByAsset(assetID crypto.Digest, filter bool } key := assetScriptKey{assetID} keyBytes := key.bytes() - if script, has := ss.cache.get(keyBytes); has { - return &script, nil - } + //if script, has := ss.cache.get(keyBytes); has { + // return &script, nil + //} tree, err := ss.newestScriptAstByKey(keyBytes, filter) if err != nil { return nil, err } - ss.cache.set(keyBytes, *tree, scriptSize) + //ss.cache.set(keyBytes, *tree, scriptSize) return tree, nil } +func (ss *scriptsStorage) newestBytecodeByAsset(assetID crypto.Digest, filter bool) (*ride.Executable, error) { + if r, ok := ss.uncertainAssetScripts[assetID]; ok { + if r.scriptIsEmpty() { + return nil, proto.ErrNotFound + } + return scriptBytesToExecutable(r.script) + } + key := assetScriptKey{assetID} + keyBytes := key.bytes() + if script, has := ss.cache.get(keyBytes); has { + return script, nil + } + exe, err := ss.newestBytecodeByKey(keyBytes, filter) + if err != nil { + return nil, err + } + ss.cache.set(keyBytes, exe, scriptSize) + return exe, nil +} + func (ss *scriptsStorage) scriptByAsset(assetID crypto.Digest, filter bool) (*ride.Tree, error) { key := assetScriptKey{assetID} return ss.scriptTreeByKey(key.bytes(), filter) @@ -305,7 +415,7 @@ func (ss *scriptsStorage) newestScriptBytesByAsset(assetID crypto.Digest, filter return ss.newestScriptBytesByKey(key.bytes(), filter) } -func (ss *scriptsStorage) setAccountScript(addr proto.Address, script proto.Script, pk crypto.PublicKey, blockID proto.BlockID) error { +func (ss *scriptsStorage) setAccountScript(addr proto.Address, script proto.Script, pk crypto.PublicKey, blockID proto.BlockID, txID string) error { key := accountScriptKey{addr} keyBytes := key.bytes() keyStr := string(keyBytes) @@ -319,7 +429,7 @@ func (ss *scriptsStorage) setAccountScript(addr proto.Address, script proto.Scri return err } } - return ss.setScript(accountScript, keyBytes, record, blockID) + return ss.setScript(accountScript, keyBytes, record, blockID, txID) } func (ss *scriptsStorage) newestAccountHasVerifier(addr proto.Address, filter bool) (bool, error) { @@ -370,14 +480,20 @@ func (ss *scriptsStorage) accountHasScript(addr proto.Address, filter bool) (boo func (ss *scriptsStorage) newestScriptByAddr(addr proto.Address, filter bool) (*ride.Tree, error) { key := accountScriptKey{addr} keyBytes := key.bytes() - if tree, has := ss.cache.get(keyBytes); has { - return &tree, nil - } tree, err := ss.newestScriptAstByKey(keyBytes, filter) if err != nil { return nil, err } - ss.cache.set(keyBytes, *tree, scriptSize) + return tree, nil +} + +func (ss *scriptsStorage) newestBytecodeByAddr(addr proto.Address, filter bool) (*ride.Executable, error) { + key := accountScriptKey{addr} + keyBytes := key.bytes() + tree, err := ss.newestBytecodeByKey(keyBytes, filter) + if err != nil { + return nil, err + } return tree, nil } diff --git a/pkg/state/scripts_storage_test.go b/pkg/state/scripts_storage_test.go index 184ad072ad..372f51c8e8 100644 --- a/pkg/state/scripts_storage_test.go +++ b/pkg/state/scripts_storage_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/util/common" ) @@ -82,9 +83,9 @@ func TestSetAccountScript(t *testing.T) { accountHasVerifier, err = to.scriptsStorage.accountHasVerifier(addr, true) assert.NoError(t, err, "accountHasVerifier() failed") assert.Equal(t, true, accountHasVerifier) - scriptAst, err = to.scriptsStorage.scriptByAddr(addr, true) + scriptAst2, err := to.scriptsStorage.scriptByAddr(addr, true) assert.NoError(t, err, "scriptByAddr() failed after flushing") - assert.Equal(t, testGlobal.scriptAst, scriptAst) + assert.Equal(t, testGlobal.scriptAst, scriptAst2) // Test discarding script. err = to.scriptsStorage.setAccountScript(addr, proto.Script{}, testGlobal.senderInfo.pk, blockID0) @@ -107,9 +108,9 @@ func TestSetAccountScript(t *testing.T) { accountHasVerifier, err = to.scriptsStorage.accountHasVerifier(addr, true) assert.NoError(t, err, "accountHasVerifier() failed") assert.Equal(t, true, accountHasVerifier) - scriptAst, err = to.scriptsStorage.scriptByAddr(addr, true) + scriptAst3, err := to.scriptsStorage.scriptByAddr(addr, true) assert.NoError(t, err) - assert.Equal(t, testGlobal.scriptAst, scriptAst) + assert.Equal(t, testGlobal.scriptAst, scriptAst3) to.stor.flush(t) @@ -177,9 +178,9 @@ func TestSetAssetScript(t *testing.T) { isSmartAsset, err = to.scriptsStorage.isSmartAsset(assetID, true) assert.NoError(t, err, "isSmartAsset() failed") assert.Equal(t, true, isSmartAsset) - scriptAst, err = to.scriptsStorage.scriptByAsset(assetID, true) + scriptAst2, err := to.scriptsStorage.scriptByAsset(assetID, true) assert.NoError(t, err, "scriptByAsset() failed after flushing") - assert.Equal(t, testGlobal.scriptAst, scriptAst) + assert.Equal(t, testGlobal.scriptAst, scriptAst2) // Test discarding script. err = to.scriptsStorage.setAssetScript(assetID, proto.Script{}, testGlobal.senderInfo.pk, blockID0) @@ -195,9 +196,9 @@ func TestSetAssetScript(t *testing.T) { isSmartAsset, err = to.scriptsStorage.isSmartAsset(assetID, true) assert.NoError(t, err, "isSmartAsset() failed") assert.Equal(t, true, isSmartAsset) - scriptAst, err = to.scriptsStorage.scriptByAsset(assetID, true) + scriptAst2, err = to.scriptsStorage.scriptByAsset(assetID, true) assert.NoError(t, err) - assert.Equal(t, testGlobal.scriptAst, scriptAst) + assert.Equal(t, testGlobal.scriptAst, scriptAst2) to.stor.flush(t) @@ -245,3 +246,18 @@ func TestSetAssetScript(t *testing.T) { assert.NoError(t, err) assert.Equal(t, testGlobal.scriptAst, scriptAst) } + +func TestScriptRecord(t *testing.T) { + kp, _ := proto.NewKeyPair([]byte("test")) + r := scriptRecord{ + pk: kp.Public, + script: []byte{1, 2, 3}, + bytecode: []byte{4, 5, 6}, + } + bytes, _ := r.marshalBinary() + + r2 := scriptRecord{} + _ = r2.unmarshalBinary(bytes) + + require.Equal(t, r, r2) +} diff --git a/pkg/state/transaction_checker.go b/pkg/state/transaction_checker.go index 081cc99bdd..7de8552e90 100644 --- a/pkg/state/transaction_checker.go +++ b/pkg/state/transaction_checker.go @@ -99,7 +99,7 @@ func (tc *transactionChecker) checkScriptComplexity(tree *ride.Tree, estimation } func (tc *transactionChecker) checkScript(script proto.Script, estimatorVersion int) (map[int]ride.TreeEstimation, error) { - tree, err := ride.Parse(script) + tree, err := scriptBytesToTree(script) if err != nil { return nil, errs.Extend(err, "failed to build AST") } diff --git a/pkg/state/transaction_performer.go b/pkg/state/transaction_performer.go index d4e9216f2c..a7f46c0d97 100644 --- a/pkg/state/transaction_performer.go +++ b/pkg/state/transaction_performer.go @@ -3,6 +3,7 @@ package state import ( "math/big" + "github.com/mr-tron/base58/base58" "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" @@ -59,7 +60,7 @@ func (tp *transactionPerformer) performIssueWithSig(transaction proto.Transactio if err != nil { return err } - if err := tp.stor.scriptsStorage.setAssetScript(assetID, proto.Script{}, tx.SenderPK, info.blockID); err != nil { + if err := tp.stor.scriptsStorage.setAssetScript(assetID, proto.Script{}, tx.SenderPK, info.blockID, "performIssueWithSig"); err != nil { return err } return tp.performIssue(&tx.Issue, assetID, info) @@ -78,7 +79,7 @@ func (tp *transactionPerformer) performIssueWithProofs(transaction proto.Transac if err != nil { return err } - if err := tp.stor.scriptsStorage.setAssetScript(assetID, tx.Script, tx.SenderPK, info.blockID); err != nil { + if err := tp.stor.scriptsStorage.setAssetScript(assetID, tx.Script, tx.SenderPK, info.blockID, "performIssueWithProofs"); err != nil { return err } return tp.performIssue(&tx.Issue, assetID, info) @@ -305,11 +306,16 @@ func (tp *transactionPerformer) performSetScriptWithProofs(transaction proto.Tra if !ok { return errors.New("failed to convert interface to SetScriptWithProofs transaction") } + txIDbytes, err := tx.GetID(tp.settings.AddressSchemeCharacter) + if err != nil { + return err + } + txID := base58.Encode(txIDbytes) senderAddr, err := proto.NewAddressFromPublicKey(tp.settings.AddressSchemeCharacter, tx.SenderPK) if err != nil { return err } - if err := tp.stor.scriptsStorage.setAccountScript(senderAddr, tx.Script, tx.SenderPK, info.blockID); err != nil { + if err := tp.stor.scriptsStorage.setAccountScript(senderAddr, tx.Script, tx.SenderPK, info.blockID, txID); err != nil { return errors.Wrap(err, "failed to set account script") } return nil @@ -320,7 +326,7 @@ func (tp *transactionPerformer) performSetAssetScriptWithProofs(transaction prot if !ok { return errors.New("failed to convert interface to SetAssetScriptWithProofs transaction") } - if err := tp.stor.scriptsStorage.setAssetScript(tx.AssetID, tx.Script, tx.SenderPK, info.blockID); err != nil { + if err := tp.stor.scriptsStorage.setAssetScript(tx.AssetID, tx.Script, tx.SenderPK, info.blockID, "performSetAssetScriptWithProofs"); err != nil { return errors.Wrap(err, "failed to set asset script") } return nil From 1b6f2ff77afb326e286fc8ae89945bcbeee73c8c Mon Sep 17 00:00:00 2001 From: Frozen Date: Mon, 1 Feb 2021 15:08:37 +0300 Subject: [PATCH 31/55] Passed testnet. --- pkg/ride/code_samples.go | 11 + pkg/ride/compiler2.go | 106 ----- pkg/ride/compiler2_test.go | 309 ++++++++++---- pkg/ride/compiler_assigment.go | 9 +- pkg/ride/compiler_call_system.go | 10 +- pkg/ride/compiler_call_user.go | 13 +- pkg/ride/compiler_conditional.go | 30 +- pkg/ride/compiler_func.go | 12 +- pkg/ride/compiler_helpers.go | 50 ++- pkg/ride/compiler_main.go | 13 - pkg/ride/compiler_state.go | 4 +- pkg/ride/executable.go | 8 +- pkg/ride/executable_test.go | 1 + pkg/ride/functions_predefined.go | 2 + pkg/ride/reverse_tree.go | 382 +++++++++-------- pkg/ride/reverse_tree_test.go | 701 ------------------------------- pkg/ride/tree_evaluation.go | 113 ++--- pkg/ride/tree_evaluation_test.go | 48 +-- pkg/state/script_caller.go | 66 +-- 19 files changed, 635 insertions(+), 1253 deletions(-) delete mode 100644 pkg/ride/reverse_tree_test.go diff --git a/pkg/ride/code_samples.go b/pkg/ride/code_samples.go index 76f4cfd304..e49a59229c 100644 --- a/pkg/ride/code_samples.go +++ b/pkg/ride/code_samples.go @@ -22,3 +22,14 @@ func abc() = { } 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/compiler2.go b/pkg/ride/compiler2.go index 8f20952fb3..6b9734da37 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -4,7 +4,6 @@ import ( "math" "github.com/pkg/errors" - "go.uber.org/zap" ) func ccc(f Fsm, node Node) (Fsm, error) { @@ -83,60 +82,6 @@ func CompileVerifier(txID string, tree *Tree) (*Executable, error) { return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, tree.IsDApp(), tree.HasVerifier()) } -type functionArgumentsCount = int - -//func CompileFunction(txID string, tree *Tree, name string, args proto.Arguments, isDapp bool) (*Executable, functionArgumentsCount, error) { -// //s, err := newEvaluationScope(tree.LibVersion, env) -// //if err != nil { -// // return nil, errors.Wrap(err, "failed to create scope") -// //} -// //for i, declaration := range tree.Declarations { -// // //err = s.declare(declaration) -// // //if err != nil { -// // // return nil, errors.Wrap(err, "invalid declaration") -// // //} -// // zap.S().Errorf("decl #%d ?? %s", i, Decompiler(declaration)) -// //} -// if !tree.IsDApp() { -// return nil, 0, errors.Errorf("unable to call function '%s' on simple script", name) -// } -// for i := 0; i < len(tree.Functions); i++ { -// function, ok := tree.Functions[i].(*FunctionDeclarationNode) -// if !ok { -// return nil, 0, errors.New("invalid callable declaration") -// } -// if function.Name == name { -// //s.constants[function.invocationParameter] = esConstant{c: newInvocation} -// //if l := len(args); l != len(function.Arguments) { -// // return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) -// //} -// //applyArgs := make([]rideType, 0, len(args)) -// //for _, arg := range args { -// // a, err := convertArgument(arg) -// // if err != nil { -// // return nil, errors.Wrapf(err, "failed to call function '%s'", name) -// // } -// // //s.pushValue(function.Arguments[i], a) -// // applyArgs = append(applyArgs, a) -// // //namedArgument{ -// // // name: function.Arguments[i], -// // // arg: a, -// // //}) -// //} -// -// rs, err := compileFunction(txID, tree.LibVersion, append(tree.Declarations, function), isDapp, tree.HasVerifier()) -// if err != nil { -// return rs, 0, err -// } -// return rs, len(function.Arguments), nil -// //return &treeEvaluator{dapp: true, f: function.Body, s: s, env: env}, nil -// } -// } -// return nil, 0, errors.Errorf("function '%s' not found", name) -// -// //return compileFunction(t.LibVersion, t) -//} - func CompileDapp(txID string, tree *Tree) (*Executable, error) { if !tree.IsDApp() { return nil, errors.Errorf("unable to compile dappp") @@ -148,52 +93,6 @@ func CompileDapp(txID string, tree *Tree) (*Executable, error) { return compileFunction(txID, tree.LibVersion, append(tree.Declarations, fns...), true, tree.HasVerifier()) } -//func CompileFlatDapp(txID string, tree *Tree) (*Executable, error) { -// if !tree.IsDApp() { -// return nil, errors.Errorf("unable to compile dappp") -// } -// fns := tree.Functions -// if tree.HasVerifier() { -// fns = append(fns, tree.Verifier) -// } -// return compileFunction(txID, tree.LibVersion, append(tree.Declarations, fns...), true, tree.HasVerifier()) -//} - -/* -func compileVerifier(libVersion int, node Node) (*Executable, error) { - fCheck, err := selectFunctionChecker(libVersion) - if err != nil { - return nil, err - } - u := &uniqid{} - b := newBuilder() - r := newReferences(nil) - c := newCell() - b.writeByte(OpReturn) - - params := params{ - b: b, - r: r, - f: fCheck, - u: u, - c: c, - } - for k, v := range predefinedFunctions { - params.addPredefined(k, v.id, v.f) - } - - f := NewMain(params) - f, err = ccc(f, node) - if err != nil { - return nil, err - } - // Just to write `OpReturn` to bytecode. - f = f.Return() - - return f.(BuildExecutable).BuildExecutable(libVersion), nil -} -*/ - func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool, hasVerifier bool) (*Executable, error) { fCheck, err := selectFunctionChecker(libVersion) if err != nil { @@ -219,7 +118,6 @@ func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool, has f := NewMain(params) for _, node := range nodes { - zap.S().Error(Decompiler(node)) f, err = ccc(f, node) if err != nil { return nil, err @@ -237,7 +135,3 @@ func CompileTree(tx string, tree *Tree) (*Executable, error) { } return CompileVerifier(tx, tree) } - -//func CompileTree(tx string, tree *Tree) (*Executable, error) { -// return CompileFlatTree(tree) -//} diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 18d90d7ece..003d53a570 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -13,37 +13,41 @@ import ( "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" ) +var defaultState = &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, +} +var defaultEnv = &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return defaultState + }, + schemeFunc: func() byte { + return 'T' + }, + thisFunc: func() rideType { + return rideAddress{} + }, + invocationFunc: func() rideObject { + return rideObject{} + }, +} + func Test22(t *testing.T) { - 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") - }, - RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { - v, err := strconv.ParseInt(key, 10, 64) - if err != nil { - return nil, err - } - return &proto.IntegerDataEntry{ - Value: v, - }, nil - }, - } - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - thisFunc: func() rideType { - return rideAddress{} - }, - } + env := defaultEnv for _, test := range []struct { comment string source string @@ -81,6 +85,7 @@ func Test22(t *testing.T) { {`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true}, {fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false}, {finf, "BAoBAAAAA2FiYwAAAAAKAQAAAAJpbgAAAAAGCQEAAAACaW4AAAAACQEAAAADYWJjAAAAADpBKyM=", env, true}, + {intersectNames, "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}, @@ -137,7 +142,9 @@ func TestCallExternal(t *testing.T) { OpReturn, OpReturn, OpRef, 0, 3, + OpCache, 0, 3, OpRef, 0, 4, + OpCache, 0, 4, OpExternalCall, 0, 3, 0, 2, OpReturn, }, @@ -362,8 +369,6 @@ func TestIfStmt(t *testing.T) { } /* - - {-# STDLIB_VERSION 3 #-} {-# CONTENT_TYPE DAPP #-} {-# SCRIPT_TYPE ACCOUNT #-} @@ -384,7 +389,6 @@ func cba(question: String) = { */ func TestDappMultipleFunctions(t *testing.T) { source := "AAIDAAAAAAAAAAwIARIDCgEIEgMKAQgAAAAAAAAAAgAAAAFpAQAAAANhYmMAAAABAAAACHF1ZXN0aW9uCQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFhAAAAAAAAAAAFBQAAAANuaWwAAAABaQEAAAADY2JhAAAAAQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQAAAAAAAAAABgUAAAADbmlsAAAAAFEpRso=" - src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) @@ -396,7 +400,7 @@ func TestDappMultipleFunctions(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - rs, err := script.Invoke(nil, "abc", []rideType{rideString(""), rideString("")}) + rs, err := script.Invoke(defaultEnv, "abc", []rideType{rideString("")}) require.NoError(t, err) require.Equal(t, true, rs.Result()) @@ -407,7 +411,7 @@ func TestDappMultipleFunctions(t *testing.T) { }, }, []proto.ScriptAction(rs.ScriptActions())) - rs, err = script.Invoke(nil, "cba", []rideType{rideString(""), rideString("")}) + rs, err = script.Invoke(defaultEnv, "cba", []rideType{rideString("")}) require.NoError(t, err) require.Equal(t, true, rs.Result()) @@ -729,10 +733,19 @@ func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) */ func TestDappVerifyVm(t *testing.T) { source := `AAIDAAAAAAAAAAIIAQAAAAAAAAAAAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAfQAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAAIBQAAAAJ0eAAAAA9zZW5kZXJQdWJsaWNLZXlQ99ml` - src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + schemeFunc: func() byte { + return 'S' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + } + tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) @@ -741,7 +754,7 @@ func TestDappVerifyVm(t *testing.T) { require.NoError(t, err) assert.NotNil(t, script) - rs, err := script.Verify(nil) + rs, err := script.Verify(env) require.NoError(t, err) require.Equal(t, rs.Result(), true) } @@ -886,6 +899,39 @@ func TestCacheInMain(t *testing.T) { 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) { + source := `BAoBAAAAA2FiYwAAAAAJAABkAAAAAgAAAAAAAAAAAQAAAAAAAAAAAQQAAAAEaW5mbwkBAAAAA2FiYwAAAAAJAAAAAAAAAgUAAAAEaW5mbwUAAAAEaW5mby35E+E=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + script, err := CompileVerifier("", tree) + require.NoError(t, err) + assert.NotNil(t, script) + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + } + + rs, err := script.Verify(env) + require.NoError(t, err) + require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, true, rs.Result()) +} + /* {-# STDLIB_VERSION 4 #-} {-# CONTENT_TYPE EXPRESSION #-} @@ -1072,57 +1118,6 @@ func TestDDaa(t *testing.T) { require.Equal(t, 4, len(script.EntryPoints)) } -/* - - - */ - -func TestRandomScript(t *testing.T) { - source := `AAIDAAAAAAAAAAgIARIECgIIAgAAAAYAAAAACVJTQVBVQkxJQwkAAlsAAAABAgAAAY9iYXNlNjQ6TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFxbEFpQU5TbUJwREhZS1A5c0tnZU4vbDFiQWIyOGcvdEdsZ0Rrd1Q1RmlNTjRYM3B3ZHZkeEU3bXZTUjgvNDFkVTlyeDRqRys2dFpwYjFVTFZEUHM0MzF0UjJJUmFUWHc1Q2orQWMydmhMKzVKYW1DZXJHRDFVVytiaC9FR1F0eG84VzNZTERyb2ZYQjVRSEp4NFBrejJLZ2Yrb1MvQzhoSHVCL1U0a3JPNzZVMDUwN0dUalpQUDlrUlEwdUxTTWVxUVh0OHdYUytuTXA1d2FqcXhQcERMTWFTUkVnc0t3di9BRWtQNGR6cFRZYmlrTEJZbDRxdGRKc0Q4NEhMRlNraXdkM0JoY09yUGpvSVltTHhRdUJENVRJTUtUS0Qzc2RaZ2FZOXJzeXF4M0EwMGlubnl4RDZ6cDNiNGdGcFVPWDhKeEtaZEVDMm15RXFsZU5nZzdHendJREFRQUIAAAAABlNFUlZFUgkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzTkNpRzI4TG1XeVRpZ1dHMTNFNVFudmRIQnNaRllYU1MyagEAAAAJUmFuZFRvU3RyAAAAAQAAAAFyAwMJAABnAAAAAgUAAAABcgAAAAAAAAAAAQkAAGcAAAACAAAAAAAAAABkBQAAAAFyBwkAAaQAAAABBQAAAAFyCQAAAgAAAAEJAAEsAAAAAgIAAAA8VW5zdXBwb3J0ZWQgciBwYXJhbWV0ZXIgcGFzc2VkOiBleHBlY3RlZD1bMSwuLi4sMTAwXSBhY3R1YWw9CQABpAAAAAEFAAAAAXIBAAAAA2FicwAAAAEAAAADdmFsAwkAAGYAAAACAAAAAAAAAAAABQAAAAN2YWwJAQAAAAEtAAAAAQUAAAADdmFsBQAAAAN2YWwBAAAACE5leHRSYW5kAAAAAgAAAA1jdXJyUmFuZHNWZWN0AAAADXJlbWFpbmluZ0hhc2gEAAAAC25leHRSYW5kSW50CQEAAAADYWJzAAAAAQkABLEAAAABBQAAAA1yZW1haW5pbmdIYXNoBAAAAAxuZXh0UmFuZFZlY3QJAAGaAAAAAQUAAAALbmV4dFJhbmRJbnQEAAAAAXMJAABpAAAAAgkAAMgAAAABBQAAAA1jdXJyUmFuZHNWZWN0AAAAAAAAAAAICQAETAAAAAIFAAAADG5leHRSYW5kVmVjdAkABEwAAAACCQAAygAAAAIFAAAADXJlbWFpbmluZ0hhc2gAAAAAAAAAAAEFAAAAA25pbAEAAAASR2VuZXJhdGVSYW5kVmVjdG9yAAAAAwAAAAlzZXNzaW9uSWQAAAABcwAAAAdyc2FTaWduBAAAAAhlbXB0eVZlYwkAAZsAAAABAgAAAAAEAAAAC3JzYVNpZ1ZhbGlkCQAB+AAAAAQFAAAABlNIQTI1NgkAAZsAAAABBQAAAAlzZXNzaW9uSWQFAAAAB3JzYVNpZ24FAAAACVJTQVBVQkxJQwMFAAAAC3JzYVNpZ1ZhbGlkBAAAAAhyYW5kSGFzaAkAAfcAAAABBQAAAAdyc2FTaWduBAAAAAluZXh0SW5mbzEJAQAAAAhOZXh0UmFuZAAAAAIFAAAACGVtcHR5VmVjBQAAAAhyYW5kSGFzaAkAAZEAAAACCQEAAAAITmV4dFJhbmQAAAACCQABkQAAAAIFAAAACW5leHRJbmZvMQAAAAAAAAAAAAkAAZEAAAACBQAAAAluZXh0SW5mbzEAAAAAAAAAAAEAAAAAAAAAAAAJAAACAAAAAQIAAAAVSW52YWxpZCBSU0Egc2lnbmF0dXJlAAAAAQAAAAFpAQAAAAZyYW5kb20AAAACAAAACXNlc3Npb25JZAAAAAdyc2FTaWduBAAAAAhjdXJyVmVjdAkBAAAAEkdlbmVyYXRlUmFuZFZlY3RvcgAAAAMFAAAACXNlc3Npb25JZAAAAAAAAAAACgUAAAAHcnNhU2lnbgQAAAABcwkAAMgAAAABBQAAAAhjdXJyVmVjdAQAAAAFcmFuZDEDCQAAZwAAAAIFAAAAAXMAAAAAAAAAAAEJAAGkAAAAAQkABLEAAAABCQAAyQAAAAIJAADKAAAAAgUAAAAIY3VyclZlY3QAAAAAAAAAAAAAAAAAAAAAAAgCAAAAAAQAAAAFcmFuZDIDCQAAZwAAAAIFAAAAAXMAAAAAAAAAAAIJAAEsAAAAAgkAASwAAAACBQAAAAVyYW5kMQIAAAABXwkAAaQAAAABCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAAhjdXJyVmVjdAkAAGgAAAACAAAAAAAAAAABAAAAAAAAAAAIAAAAAAAAAAAIBQAAAAVyYW5kMQkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAARR2VuZXJhdGVkX051bWJlcnMFAAAABXJhbmQyBQAAAANuaWwAAAAAKwqyHg==` - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - assert.NotNil(t, tree) - - script, err := CompileTree("", tree) - require.NoError(t, err) - assert.NotNil(t, script) - - //ser := NewSerializer() - //err = script.Serialize(ser) - //require.NoError(t, err) - - //deser := NewDeserializer() - //script, err = DeserializeExecutable(ser.Source()) - //require.NoError(t, err) - - env := &MockRideEnvironment{ - transactionFunc: testExchangeWithProofsToObject, - checkMessageLengthFunc: func(in1 int) bool { - return true - }, - } - - //random("123123123", "base64:RBuQVdRoLd+fCs0ZZLeHH1WG+oV2a8bLIl4TJow4Qkyqsp/5+4V0LlC+kiPRQuurcackzAgQFZPzV1wNvcVDO+wlFg+gzguL4D382XFClWZ6w+fE/WUrb5Bt893k0Bz7UeEsCu9pDfy41eC1gWDGt0qvKFu+la5MPx/dq10bjVu+2JlBWF2ZBMPD0rrpe+2ZE/JVcaNv+Hf6PS16eHhhiA5Ydsoynsv7vIdZw6atux7J/0VhxxOAUj+LKt92ayBakS5sUnfeOVG1P5Dc9DI1A6MxEK/Xs1ii6NaSaQgU+hWD+472tq47iG4E493wBKHSVV6GP45VLxn23CBBjogeOQ==") - - bts, err := base64.StdEncoding.DecodeString("RBuQVdRoLd+fCs0ZZLeHH1WG+oV2a8bLIl4TJow4Qkyqsp/5+4V0LlC+kiPRQuurcackzAgQFZPzV1wNvcVDO+wlFg+gzguL4D382XFClWZ6w+fE/WUrb5Bt893k0Bz7UeEsCu9pDfy41eC1gWDGt0qvKFu+la5MPx/dq10bjVu+2JlBWF2ZBMPD0rrpe+2ZE/JVcaNv+Hf6PS16eHhhiA5Ydsoynsv7vIdZw6atux7J/0VhxxOAUj+LKt92ayBakS5sUnfeOVG1P5Dc9DI1A6MxEK/Xs1ii6NaSaQgU+hWD+472tq47iG4E493wBKHSVV6GP45VLxn23CBBjogeOQ==") - require.NoError(t, err) - - arguments := proto.Arguments{} - arguments.Append(&proto.StringArgument{Value: "123123123"}) - arguments.Append(&proto.BinaryArgument{Value: bts}) - - rs, err := CallTreeFunction(env, tree, "random", arguments) - //rs, err := script.Invoke(env, "random", []rideType{rideUnit{}, rideString("123123123"), rideBytes(bts)}) - //for i, c := range rs.Calls() { - // t.Log(i, c) - //} - require.NoError(t, err) - require.Equal(t, rs.Result(), true) -} - func BenchmarkVm(b *testing.B) { source := "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=" src, err := base64.StdEncoding.DecodeString(source) @@ -1298,9 +1293,6 @@ func BenchmarkTreeWithDeserialize(b *testing.B) { source := "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=" src, err := base64.StdEncoding.DecodeString(source) require.NoError(b, err) - // - //tree, err := Parse(src) - //require.NoError(b, err) state := &MockSmartState{ NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { @@ -1347,3 +1339,138 @@ func BenchmarkTreeWithDeserialize(b *testing.B) { require.Equal(b, 5, len(rs.Calls())) } } + +/* +{-# 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) { + source := `BAMGCgEAAAABYQAAAAAGCQEAAAABYQAAAAAKAQAAAAFiAAAAAAcJAQAAAAFiAAAAAObLaEQ=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + NewestAccountBalanceFunc: func(account proto.Recipient, asset []byte) (uint64, error) { + return 0, nil + }, + } + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + stateFunc: func() types.SmartState { + return state + }, + thisFunc: func() rideType { + return rideAddress{} + }, + } + + tree, err := Parse(src) + require.NoError(t, err) + rs1, err := CallTreeVerifier(env, tree) + for i, c := range rs1.Calls() { + t.Log(i, " ", c) + } + + exe, err := CompileTree("", tree) + require.NoError(t, err) + + rs2, err := exe.Verify(env) + require.NoError(t, err) + for i, c := range rs2.Calls() { + t.Log(i, " ", c) + } + require.True(t, rs1.Eq(rs2)) +} + +/* + + */ + +func Test111111(t *testing.T) { + source := `AwoBAAAAA2luYwAAAAEAAAABdgkAAGQAAAACBQAAAAF2AAAAAAAAAAABCgEAAAAEY2FsbAAAAAEAAAADaW5jCQEAAAADaW5jAAAAAQUAAAADaW5jCQAAAAAAAAIJAQAAAARjYWxsAAAAAQAAAAAAAAAAAgAAAAAAAAAAAxgTXMY=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + state := &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + NewestAccountBalanceFunc: func(account proto.Recipient, asset []byte) (uint64, error) { + return 0, nil + }, + } + + env := &MockRideEnvironment{ + transactionFunc: testExchangeWithProofsToObject, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + stateFunc: func() types.SmartState { + return state + }, + thisFunc: func() rideType { + return rideAddress{} + }, + invocationFunc: func() rideObject { + return rideObject{} + }, + } + + tree, err := Parse(src) + require.NoError(t, err) + //rs, err := CallTreeVerifier(env, tree) + //for i, c := range rs.Calls() { + // t.Log(i, " ", c) + //} + + exe, err := CompileTree("", tree) + require.NoError(t, err) + rs, err := exe.Verify(env) + require.NoError(t, err) + for i, c := range rs.Calls() { + t.Log(i, " ", c) + } +} diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 4621714379..e215392dde 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -8,9 +8,6 @@ type AssigmentState struct { bodyParams params prev Fsm name string - //startedAt uint16 - //ret uint16 - //constant rideType // ref id n uniqueid @@ -60,7 +57,7 @@ func (a AssigmentState) Boolean(v bool) Fsm { } func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid, d Deferreds) Fsm { - params.r.set(name, n) + params.r.setAssigment(name, n) return newAssigmentFsm(prev, params, name, n, d) } @@ -90,7 +87,7 @@ func (a AssigmentState) Assigment(name string) Fsm { } func (a AssigmentState) Return() Fsm { - a.r.set(a.name, a.n) + a.r.setAssigment(a.name, a.n) a.d.Add(a, a.n, fmt.Sprintf("ref %s", a.name)) return a.prev } @@ -121,8 +118,6 @@ func (a AssigmentState) Write(_ params, b []byte) { } func (a AssigmentState) Clean() { - //for i := len(a.assigments) - 1; i >= 0; i-- { a.b.writeByte(OpClearCache) a.b.write(encode(a.n)) - //} } diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index d97952cc84..dd251dd8ee 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -15,7 +15,8 @@ type CallSystemState struct { //retAssig uint16 deferred []Deferred deferreds Deferreds - ns []uniqueid + // Sequential function arguments. + ns []uniqueid } func (a CallSystemState) backward(state Fsm) Fsm { @@ -59,7 +60,7 @@ func (a CallSystemState) Boolean(value bool) Fsm { } func callTransition(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { - if _, ok := params.r.get(name); ok { + if _, ok := params.r.getFunc(name); ok { return newCallUserFsm(prev, params, name, argc, d) } return newCallSystemFsm(prev, params, name, argc, d) @@ -85,7 +86,6 @@ func newCallSystemFsm(prev Fsm, params params, name string, argc uint16, d Defer func (a CallSystemState) Assigment(name string) Fsm { n := a.params.u.next() return assigmentFsmTransition(a, a.params, name, n, a.deferreds) - //panic(fmt.Sprintf("CallSystemState Assigment %s", a.params.txID)) } func (a CallSystemState) Long(value int64) Fsm { @@ -135,10 +135,14 @@ func (a CallSystemState) Write(_ params, b []byte) { if n, ok := isConstant(a.deferred[i]); ok { a.b.writeByte(OpRef) a.b.write(encode(n)) + a.b.writeByte(OpCache) + a.b.write(encode(n)) } else { n := a.ns[i] a.b.writeByte(OpRef) a.b.write(encode(n)) + //a.b.writeByte(OpCache) + //a.b.write(encode(n)) } } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 79f317a2ca..3bf1a0628d 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -140,7 +140,7 @@ func (a CallUserState) Clean() { func (a CallUserState) Write(_ params, b []byte) { // check user functions - fn, ok := a.r.get(a.name) + fn, ok := a.r.getFunc(a.name) if !ok { panic(fmt.Sprintf("user function `%s` not found", a.name)) } @@ -155,16 +155,17 @@ func (a CallUserState) Write(_ params, b []byte) { a.b.writeByte(OpRef) a.b.write(encode(n)) a.b.writeByte(OpCache) - a.b.write(encode(fn + 1 + i)) - a.b.writeByte(OpPop) + a.b.write(encode(n)) + //a.b.write(encode(fn + 1 + i)) + //a.b.writeByte(OpPop) ns = append(ns, n) } else { n := a.u.next() a.b.writeByte(OpRef) a.b.write(encode(n)) - a.b.writeByte(OpCache) - a.b.write(encode(fn + 1 + i)) - a.b.writeByte(OpPop) + //a.b.writeByte(OpCache) + //a.b.write(encode(fn + 1 + i)) + //a.b.writeByte(OpPop) ns = append(ns, n) } } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 43b1b28331..7184667400 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -1,5 +1,9 @@ package ride +import "fmt" + +//import "fmt" + // If-else statement. type ConditionalState struct { params @@ -16,7 +20,6 @@ type ConditionalState struct { } `X` and `y` should not be executed. - */ patchTruePosition uint16 // Same as true position. @@ -36,8 +39,13 @@ type ConditionalState struct { condN uniqueid } -func (a ConditionalState) backward(v Fsm) Fsm { - a.deferred = append(a.deferred, v.(Deferred)) +func (a ConditionalState) backward(as Fsm) Fsm { + // Func in func. + if f, ok := as.(FuncState); ok { + a.deferreds.Add(as.(Deferred), f.n, fmt.Sprintf("func `%s`in conditional", f.name)) + } else { + a.deferred = append(a.deferred, as.(Deferred)) + } return a } @@ -46,7 +54,8 @@ func (a ConditionalState) Property(name string) Fsm { } func (a ConditionalState) Func(name string, args []string, invoke string) Fsm { - panic("Illegal call Func on ConditionalState") + //panic(fmt.Sprintf("Illegal call Func on ConditionalState %s", a.txID)) + return funcTransition(a, a.params, name, args, invoke) } func (a ConditionalState) Bytes(value []byte) Fsm { @@ -80,7 +89,7 @@ func (a ConditionalState) FalseBranch() Fsm { func (a ConditionalState) Assigment(name string) Fsm { n := a.params.u.next() //a.assigments = append(a.assigments, n) - a.r.set(name, n) + a.r.setAssigment(name, n) return assigmentFsmTransition(a, a.params, name, n, a.deferreds) } @@ -90,15 +99,10 @@ func (a ConditionalState) Long(value int64) Fsm { } func (a ConditionalState) Call(name string, argc uint16) Fsm { - //a.rets = append(a.rets, a.params.b.len()) return callTransition(a, a.params, name, argc, a.deferreds) - //panic("") } func (a ConditionalState) Reference(name string) Fsm { - //a.rets = append(a.rets, a.params.b.len()) - //return reference(a, a.params, name) - //panic("") a.deferred = append(a.deferred, reference(a, a.params, name)) return a } @@ -114,12 +118,12 @@ func (a ConditionalState) String(value string) Fsm { } func (a ConditionalState) Return() Fsm { - if len(a.deferred) != 3 { - panic("len(a.deferred) != 3") + if len(a.deferred) < 3 { + panic("len(a.deferred) < 3") } a.condN = a.u.next() a.deferreds.Add(a.deferred[0], a.condN, "condition cond") - return a.prev.backward(a) //.backward(a.startedAt, a.b.len()) + return a.prev.backward(a) } func (a ConditionalState) Write(_ params, b []byte) { diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index a6bbf7e526..38fee03a13 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -63,8 +63,8 @@ func (a FuncState) Property(name string) Fsm { func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { argn := len(args) n := params.u.next() - params.r.set(name, n) - // all variable we add only visible to current scope, + params.r.setFunc(name, n) + // All variable we add only visible to current scope, // avoid corrupting global scope. params.r = newReferences(params.r) @@ -76,7 +76,7 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP for i := range args { e := params.u.next() paramIds = append(paramIds, e) - params.r.set(args[i], e) + params.r.setAssigment(args[i], e) } return &FuncState{ @@ -162,6 +162,12 @@ func (a FuncState) Write(_ params, b []byte) { if len(a.deferred) != 1 { panic("len(a.deferred) != 1") } + // Assign function arguments from stack. + for i := len(a.paramIds) - 1; i >= 0; i-- { + a.b.writeByte(OpCache) + a.b.write(encode(a.paramIds[i])) + a.b.writeByte(OpPop) + } a.deferred[0].Write(a.params, nil) // End of function body. Clear and write assigments. diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 9b780e9b8c..080d711129 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -218,30 +218,62 @@ func (a *cell) get(u uniqueid) (point, bool) { type uniqueid = uint16 +type refKind struct { + assigment bool + n uniqueid +} + type references struct { prev *references - refs map[string]uint16 + refs map[string][]refKind } func newReferences(prev *references) *references { return &references{ prev: prev, - refs: make(map[string]uint16), + refs: make(map[string][]refKind), } } -func (a *references) get(name string) (uniqueid, bool) { +//func (a *references) get(name string) (uniqueid, bool) { +// if a == nil { +// return 0, false +// } +// if offset, ok := a.refs[name]; ok { +// return offset, ok +// } +// return a.prev.get(name) +//} + +func (a *references) setAssigment(name string, uniq uniqueid) { + a.refs[name] = append([]refKind{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) getFunc(name string) (uniqueid, bool) { + return a.get(name, false) +} + +func (a *references) getAssigment(name string) (uniqueid, bool) { + return a.get(name, true) +} + +func (a *references) get(name string, assigment bool) (uniqueid, bool) { if a == nil { return 0, false } if offset, ok := a.refs[name]; ok { - return offset, ok + for _, v := range offset { + if v.assigment == assigment { + return v.n, true + } + } + return a.prev.get(name, assigment) } - return a.prev.get(name) -} - -func (a *references) set(name string, uniq uniqueid) { - a.refs[name] = uniq + return a.prev.get(name, assigment) } func (a *references) pop() *references { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index abfb86746a..10127cd155 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -27,7 +27,6 @@ func (a MainState) Bytes(b []byte) Fsm { } func (a MainState) Condition() Fsm { - //a.b.startPos() return conditionalTransition(a, a.params, a.deferreds) } @@ -58,8 +57,6 @@ func NewMain(params params) Fsm { func (a MainState) Assigment(name string) Fsm { n := a.params.u.next() - //a.assigments = append(a.assigments, n) - //a.r.set(name, n) return assigmentFsmTransition(a, a.params, name, n, a.deferreds) } @@ -78,11 +75,6 @@ func (a MainState) Return() Fsm { if f, ok := body[0].(FuncState); ok && f.invokeParam != "" { a.b.setStart(f.name, f.argn) a.b.setStart("", 0) - for i := len(f.ParamIds()) - 1; i >= 0; i-- { - a.b.writeByte(OpCache) - a.b.write(encode(f.ParamIds()[i])) - a.b.writeByte(OpPop) - } } else { a.b.setStart("", 0) } @@ -95,11 +87,6 @@ func (a MainState) Return() Fsm { } a.b.ret() - //for _, v := range reversed[1:] { - // v.Write(a.params, nil) - // a.b.ret() - //} - for _, v := range a.deferreds.Get() { pos := a.b.len() a.c.set(v.uniq, nil, 0, pos, false, v.debug) diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 0ba40d1f28..545b393618 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -61,7 +61,7 @@ type params struct { } func (a *params) addPredefined(name string, id uniqueid, fn uint16) { - a.r.set(name, id) + a.r.setAssigment(name, id) a.c.set(id, nil, fn, 0, false, name) } @@ -72,7 +72,7 @@ func (a *params) constant(value rideType) constantDeferred { } func reference(_ Fsm, params params, name string) Deferred { - pos, ok := params.r.get(name) + pos, ok := params.r.getAssigment(name) if !ok { panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) } diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 6ff4d90e94..190808c2bb 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -23,6 +23,9 @@ func (a *Executable) Verify(environment RideEnvironment) (RideResult, error) { if !a.HasVerifier() { return nil, errors.Errorf("no verifier attached to script") } + if environment == nil { + return nil, errors.Errorf("expect to get env.transaction(), but env is nil") + } return a.runWithoutChecks(environment, "", []rideType{environment.transaction()}) } return a.runWithoutChecks(environment, "", nil) @@ -78,7 +81,7 @@ func (a *Executable) runWithoutChecks(environment RideEnvironment, name string, } } -func (a *Executable) Invoke(environment RideEnvironment, name string, arguments []rideType) (RideResult, error) { +func (a *Executable) Invoke(env RideEnvironment, name string, arguments []rideType) (RideResult, error) { if name == "" { return nil, errors.Errorf("expected func name, found \"\"") } @@ -86,10 +89,11 @@ func (a *Executable) Invoke(environment RideEnvironment, name string, arguments if !ok { return nil, errors.Errorf("function %s not found", name) } + arguments = append([]rideType{env.invocation()}, arguments...) if len(arguments) != int(fcall.argn)+1 { return nil, errors.Errorf("func `%s` requires %d arguments(1 invoke + %d args), but provided %d", name, fcall.argn+1, fcall.argn, len(arguments)) } - return a.runWithoutChecks(environment, name, arguments) + return a.runWithoutChecks(env, name, arguments) } func (a *Executable) run(environment RideEnvironment, arguments []rideType) (rideType, error) { diff --git a/pkg/ride/executable_test.go b/pkg/ride/executable_test.go index ea30ad7f3d..ee0b29d4c6 100644 --- a/pkg/ride/executable_test.go +++ b/pkg/ride/executable_test.go @@ -8,6 +8,7 @@ import ( ) func TestExecutableSerialization(t *testing.T) { + t.Skip() source := `AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==` src, err := base64.StdEncoding.DecodeString(source) require.NoError(t, err) diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index aafca92f22..c894cbbf0f 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -51,6 +51,8 @@ var predefinedFunctions = []predefFunc{ {"SHA3512", createSha3512}, {"Buy", createBuy}, {"Sell", createSell}, + {"CEILING", createCeiling}, + {"HALFEVEN", createHalfEven}, } var predefined *predef diff --git a/pkg/ride/reverse_tree.go b/pkg/ride/reverse_tree.go index 757451d0c3..46bdb1a9b2 100644 --- a/pkg/ride/reverse_tree.go +++ b/pkg/ride/reverse_tree.go @@ -1,11 +1,7 @@ package ride import ( - "bytes" "fmt" - "math" - - "github.com/pkg/errors" ) func ReverseTree(n []Node) { @@ -266,179 +262,179 @@ func (a *startpoint) evalAndPop() { // return &e, nil //} -func compileReversedTree(nodes []RNode, libVersion int, isDapp bool, hasVerifier bool) (*Executable, error) { - var condPos []uint16 - refs := newReferences(nil) - out := bytes.Buffer{} - out.WriteByte(OpReturn) - out.WriteByte(OpReturn) - c := newCell() - u := uniqid{} - u.next() - entrypoints := make(map[string]Entrypoint) - - st := startpoint{ - default_: func() { - entrypoints[""] = Entrypoint{ - name: "", - at: uint16(out.Len()), - argn: 0, - } - }, - } - st.evalAndPop() - - for k, v := range predefinedFunctions { - id := uint16(math.MaxUint16 - k) - refs.set(v.name, id) - c.set(id, nil, id, 0, false, v.name) - } - - // - for _, v := range nodes { - switch v := v.(type) { - case *RDef: - n := u.next() - refs.set(v.Name, n) - c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) - for range v.Arguments { - u.next() - } - //case *RBody: - // n, ok := refs.get(v.Name, n) - // if !ok { - // return errors.Errorf() - // } - case *RConst: - n := u.next() - c.set(n, v.Value, 0, 0, true, fmt.Sprintf("constant %q", v.Value)) - out.WriteByte(OpRef) - out.Write(encode(n)) - case *RCall: - if n, ok := refs.get(v.Name); ok { - out.WriteByte(OpRef) - out.Write(encode(n)) - continue - } - fCheck, err := selectFunctionChecker(libVersion) - if err != nil { - return nil, err - } - out.WriteByte(OpExternalCall) - id, ok := fCheck(v.Name) - if !ok { - return nil, errors.Errorf("invalid func name `%s`", v.Name) - } - out.Write(encode(id)) - out.Write(encode(v.Argn)) - case *RReferenceNode: - n, ok := refs.get(v.Name) - if !ok { - return nil, errors.Errorf("reference `%s` not found", v.Name) - } - out.WriteByte(OpRef) - out.Write(encode(n)) - case *RLet: - n := u.next() - refs.set(v.Name, n) - c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) - n, ok := refs.get(v.Name) - if !ok { - return nil, errors.Errorf("reference `%s` not found", v.Name) - } - e, ok := c.values[n] - if !ok { - return nil, errors.Errorf("cell `%d` not found", n) - } - e.position = uint16(out.Len()) - c.values[n] = e - case *RFunc: - n := u.next() - refs.set(v.Name, n) - refs = newReferences(refs) - c.set(n, nil, 0, 0, false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) - for i := range v.ArgumentsWithInvocation { - z := u.next() - c.set(z, nil, 0, 0, false, fmt.Sprintf("ref %d, func arg #%d %s", z, i, v.Name)) - refs.set(v.ArgumentsWithInvocation[i], z) - } - if v.Invocation != "" { - st.push(func() { - entrypoints[v.Name] = Entrypoint{ - name: v.Name, - at: uint16(out.Len()), - argn: uint16(len(v.Arguments)), - } - for i := len(v.Arguments) + 1; i > 0; i-- { - out.WriteByte(OpCache) - out.Write(encode(n + uint16(i))) - out.WriteByte(OpPop) - } - }) - } else { - st.push(func() { - c.set(n, nil, 0, uint16(out.Len()), false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) - for i := len(v.ArgumentsWithInvocation); i > 0; i-- { - out.WriteByte(OpCache) - out.Write(encode(n + uint16(i))) - out.WriteByte(OpPop) - } - }) - } - case *RFuncEnd: - refs = refs.pop() - - case *RRet: - out.WriteByte(OpReturn) - case *RCond: - condPos = append(condPos, uint16(out.Len())) - out.WriteByte(OpJumpIfFalse) - out.Write(make([]byte, 6)) - case *RCondTrue: - pos := condPos[len(condPos)-1] - st.push(func() { - patchBuffer(&out, pos+1, encode(uint16(out.Len()))) - }) - case *RCondFalse: - pos := condPos[len(condPos)-1] - st.push(func() { - patchBuffer(&out, pos+3, encode(uint16(out.Len()))) - }) - - case *RCondEnd: - pos := condPos[len(condPos)-1] - patchBuffer(&out, pos+5, encode(uint16(out.Len()))) - condPos = condPos[:len(condPos)-1] - case *RStart: - st.evalAndPop() - - case *RProperty: - out.WriteByte(OpProperty) - - default: - panic(fmt.Sprintf("unknown type %T", v)) - } - - } - - // Most recent code line. - out.WriteByte(OpReturn) - - if isDapp && hasVerifier { - entrypoints[""] = entrypoints["verify"] - } - - e := Executable{ - LibVersion: libVersion, - IsDapp: isDapp, - hasVerifier: hasVerifier, - ByteCode: out.Bytes(), - EntryPoints: entrypoints, - References: c.values, - } - - return &e, nil -} +//func compileReversedTree(nodes []RNode, libVersion int, isDapp bool, hasVerifier bool) (*Executable, error) { +// var condPos []uint16 +// refs := newReferences(nil) +// out := bytes.Buffer{} +// out.WriteByte(OpReturn) +// out.WriteByte(OpReturn) +// c := newCell() +// u := uniqid{} +// u.next() +// entrypoints := make(map[string]Entrypoint) +// +// st := startpoint{ +// default_: func() { +// entrypoints[""] = Entrypoint{ +// name: "", +// at: uint16(out.Len()), +// argn: 0, +// } +// }, +// } +// st.evalAndPop() +// +// for k, v := range predefinedFunctions { +// id := uint16(math.MaxUint16 - k) +// refs.setAssigment(v.name, id) +// c.set(id, nil, id, 0, false, v.name) +// } +// +// // +// for _, v := range nodes { +// switch v := v.(type) { +// case *RDef: +// n := u.next() +// refs.set(v.Name, n) +// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) +// for range v.Arguments { +// u.next() +// } +// //case *RBody: +// // n, ok := refs.get(v.Name, n) +// // if !ok { +// // return errors.Errorf() +// // } +// case *RConst: +// n := u.next() +// c.set(n, v.Value, 0, 0, true, fmt.Sprintf("constant %q", v.Value)) +// out.WriteByte(OpRef) +// out.Write(encode(n)) +// case *RCall: +// if n, ok := refs.get(v.Name); ok { +// out.WriteByte(OpRef) +// out.Write(encode(n)) +// continue +// } +// fCheck, err := selectFunctionChecker(libVersion) +// if err != nil { +// return nil, err +// } +// out.WriteByte(OpExternalCall) +// id, ok := fCheck(v.Name) +// if !ok { +// return nil, errors.Errorf("invalid func name `%s`", v.Name) +// } +// out.Write(encode(id)) +// out.Write(encode(v.Argn)) +// case *RReferenceNode: +// n, ok := refs.get(v.Name) +// if !ok { +// return nil, errors.Errorf("reference `%s` not found", v.Name) +// } +// out.WriteByte(OpRef) +// out.Write(encode(n)) +// case *RLet: +// n := u.next() +// refs.set(v.Name, n) +// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) +// n, ok := refs.get(v.Name) +// if !ok { +// return nil, errors.Errorf("reference `%s` not found", v.Name) +// } +// e, ok := c.values[n] +// if !ok { +// return nil, errors.Errorf("cell `%d` not found", n) +// } +// e.position = uint16(out.Len()) +// c.values[n] = e +// case *RFunc: +// n := u.next() +// refs.set(v.Name, n) +// refs = newReferences(refs) +// c.set(n, nil, 0, 0, false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) +// for i := range v.ArgumentsWithInvocation { +// z := u.next() +// c.set(z, nil, 0, 0, false, fmt.Sprintf("ref %d, func arg #%d %s", z, i, v.Name)) +// refs.set(v.ArgumentsWithInvocation[i], z) +// } +// if v.Invocation != "" { +// st.push(func() { +// entrypoints[v.Name] = Entrypoint{ +// name: v.Name, +// at: uint16(out.Len()), +// argn: uint16(len(v.Arguments)), +// } +// for i := len(v.Arguments) + 1; i > 0; i-- { +// out.WriteByte(OpCache) +// out.Write(encode(n + uint16(i))) +// out.WriteByte(OpPop) +// } +// }) +// } else { +// st.push(func() { +// c.set(n, nil, 0, uint16(out.Len()), false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) +// for i := len(v.ArgumentsWithInvocation); i > 0; i-- { +// out.WriteByte(OpCache) +// out.Write(encode(n + uint16(i))) +// out.WriteByte(OpPop) +// } +// }) +// } +// case *RFuncEnd: +// refs = refs.pop() +// +// case *RRet: +// out.WriteByte(OpReturn) +// case *RCond: +// condPos = append(condPos, uint16(out.Len())) +// out.WriteByte(OpJumpIfFalse) +// out.Write(make([]byte, 6)) +// case *RCondTrue: +// pos := condPos[len(condPos)-1] +// st.push(func() { +// patchBuffer(&out, pos+1, encode(uint16(out.Len()))) +// }) +// case *RCondFalse: +// pos := condPos[len(condPos)-1] +// st.push(func() { +// patchBuffer(&out, pos+3, encode(uint16(out.Len()))) +// }) +// +// case *RCondEnd: +// pos := condPos[len(condPos)-1] +// patchBuffer(&out, pos+5, encode(uint16(out.Len()))) +// condPos = condPos[:len(condPos)-1] +// case *RStart: +// st.evalAndPop() +// +// case *RProperty: +// out.WriteByte(OpProperty) +// +// default: +// panic(fmt.Sprintf("unknown type %T", v)) +// } +// +// } +// +// // Most recent code line. +// out.WriteByte(OpReturn) +// +// if isDapp && hasVerifier { +// entrypoints[""] = entrypoints["verify"] +// } +// +// e := Executable{ +// LibVersion: libVersion, +// IsDapp: isDapp, +// hasVerifier: hasVerifier, +// ByteCode: out.Bytes(), +// EntryPoints: entrypoints, +// References: c.values, +// } +// +// return &e, nil +//} type ddfrs struct { } @@ -586,22 +582,22 @@ func reverseTree3(n Node, out []RNode) []RNode { } } -func CompileFlatTree(tree *Tree) (*Executable, error) { - if tree.IsDApp() { - var rev []RNode - for _, v := range tree.Declarations { - rev = append(rev, reverseTree3(v, nil)...) - } - for _, v := range tree.Functions { - rev = append(rev, reverseTree3(v, nil)...) - } - if tree.HasVerifier() { - rev = append(rev, reverseTree3(tree.Verifier, nil)...) - } - return compileReversedTree(rev, tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) - } - return compileReversedTree(reverseTree3(tree.Verifier, nil), tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) -} +//func CompileFlatTree(tree *Tree) (*Executable, error) { +// if tree.IsDApp() { +// var rev []RNode +// for _, v := range tree.Declarations { +// rev = append(rev, reverseTree3(v, nil)...) +// } +// for _, v := range tree.Functions { +// rev = append(rev, reverseTree3(v, nil)...) +// } +// if tree.HasVerifier() { +// rev = append(rev, reverseTree3(tree.Verifier, nil)...) +// } +// return compileReversedTree(rev, tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) +// } +// return compileReversedTree(reverseTree3(tree.Verifier, nil), tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) +//} func flatCondNode(t *ConditionalNode) []RNode { var out []RNode diff --git a/pkg/ride/reverse_tree_test.go b/pkg/ride/reverse_tree_test.go deleted file mode 100644 index 003e9a2dce..0000000000 --- a/pkg/ride/reverse_tree_test.go +++ /dev/null @@ -1,701 +0,0 @@ -package ride - -import ( - "encoding/base64" - "strconv" - "testing" - - "github.com/pkg/errors" - "github.com/stretchr/testify/require" - "github.com/wavesplatform/gowaves/pkg/proto" - "github.com/wavesplatform/gowaves/pkg/types" - "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" -) - -func Test33(t *testing.T) { - 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") - }, - RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { - v, err := strconv.ParseInt(key, 10, 64) - if err != nil { - return nil, err - } - return &proto.IntegerDataEntry{ - Value: v, - }, nil - }, - } - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - thisFunc: func() rideType { - return rideAddress{} - }, - } - for _, test := range []struct { - comment string - source string - env RideEnvironment - res bool - }{ - {`V1: true`, "AQa3b8tH", env, true}, - {`V1: false`, `AQfeYll6`, nil, false}, - {`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true}, - {`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - {`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", env, true}, - {`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false}, - {`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", env, true}, - {`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true}, - {`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false}, - {`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true}, - {`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false}, - {`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true}, - {`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true}, - {`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true}, - {`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true}, - {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true}, - {`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true}, - {`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true}, - {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, - {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - {`let x = {let y = true;y}x`, `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C`, nil, true}, - {`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}, - {`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}, - {`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, false}, - {`tx.id == tx.id`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQIBQAAAAJ0eAAAAAJpZHErpOM=`, env, true}, - {`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - {`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - {`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - {`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, - {`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, env, true}, - {`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}, - } { - src, err := base64.StdEncoding.DecodeString(test.source) - require.NoError(t, err, test.comment) - - tree, err := Parse(src) - require.NoError(t, err, test.comment) - require.NotNil(t, tree, test.comment) - - exe, err := CompileFlatTree(tree) - require.NoError(t, err) - - res, err := exe.Verify(test.env) - require.NoError(t, err, test.comment) - require.NotNil(t, res, test.comment) - - t.Log(res.Calls()) - - r, ok := res.(ScriptResult) - require.True(t, ok, test.comment) - require.Equal(t, test.res, r.Result(), test.comment) - } -} - -/* -func abc(key: String) = { - let x = 1 - let y = 2 - x + y -} -*/ -/* -func TestReverseFunc(t *testing.T) { - n := &FunctionDeclarationNode{ - Name: "abc", - Arguments: []string{"key"}, - Body: &AssignmentNode{ - Name: "x", - Expression: &LongNode{Value: 1}, - Block: &AssignmentNode{ - Name: "y", - Expression: &LongNode{Value: 2}, - Block: &FunctionCallNode{ - Name: "+", - Arguments: []Node{ - &ReferenceNode{Name: "x"}, - &ReferenceNode{Name: "y"}, - }, - }, - }, - }, - } - - rs := reverseTree(n, nil) - - require.Equal(t, &RFunc{ - Invocation: "", - Name: "abc", - Arguments: []string{"key"}, - Body: &RCall{ - Name: "+", - Arguments: []RNode{ - &RRef{Name: "x"}, - &RRef{Name: "y"}, - }, - Assigments: []*RLet{ - {Name: "x", Body: &RLong{Value: 1}}, - {Name: "y", Body: &RLong{Value: 2}}, - }, - }, - }, rs) - -} - -*/ - -/* -func abc(key: String) = { - match getInteger(this, key) { - case a: Int => - a - case _ => - 0 -} -*/ -/* -func TestReverseFunc2(t *testing.T) { - n := &FunctionDeclarationNode{ - Name: "abc", - Arguments: []string{"key"}, - Body: &AssignmentNode{ - Name: "$match0", - Expression: &FunctionCallNode{ - Name: "1050", - Arguments: []Node{ - &ReferenceNode{Name: "this"}, - &ReferenceNode{Name: "key"}, - }, - }, - Block: &ConditionalNode{ - Condition: &FunctionCallNode{ - Name: "1", - Arguments: []Node{ - &ReferenceNode{Name: "$match0"}, - &StringNode{Value: "Int"}, - }, - }, - TrueExpression: &AssignmentNode{ - Name: "a", - Expression: &ReferenceNode{Name: "$match0"}, - Block: &ReferenceNode{Name: "a"}, - }, - FalseExpression: &LongNode{Value: 0}, - }, - }, - } - - rs := reverseTree(n, nil) - - require.Equal(t, &RFunc{ - Invocation: "", - Name: "abc", - Arguments: []string{"key"}, - Body: &RCond{ - Cond: &RCall{ - Name: "1", - Arguments: []RNode{ - &RRef{Name: "$match0"}, - &RString{Value: "Int"}, - }, - }, - True: &RRef{ - Name: "a", - Assigments: []*RLet{ - { - Name: "a", - Body: &RRef{Name: "$match0"}, - }, - }, - }, - False: &RLong{Value: 0}, - Assigments: []*RLet{ - {Name: "$match0", Body: &RCall{ - Name: "1050", - Arguments: []RNode{ - &RRef{Name: "this"}, - &RRef{Name: "key"}, - }, - }}, - }, - }, - //Assigments: []*RLet{ - // { - // Name: "$match0", - // N: 0, - // Body: nil, - // }, - //}, - }, rs) -} -*/ - -/* -func TestReverse2(t *testing.T) { - //{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true}, - source := `BAQAAAABeAYFAAAAAXhUb/5M` - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - require.NotNil(t, tree) - - reversed := reverseTree3(tree.Verifier, nil, nil) - require.Equal(t, []RNode{ - &RDef{Name: "x"}, - &RReferenceNode{Name: "x"}, - &RLet{Name: "x"}, - &RConst{Value: rideBoolean(true)}, - }, reversed) - - //env := &MockRideEnvironment{ - // transactionFunc: testExchangeWithProofsToObject, - //} - // - //rs, err := script.Run(env, nil) - //require.NoError(t, err) - //require.Equal(t, 2, len(rs.Calls())) - //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 TestMultipleProperty2(t *testing.T) { - source := `AwQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE0V4Y2hhbmdlVHJhbnNhY3Rpb24EAAAAAWUFAAAAByRtYXRjaDAJAQAAAAlpc0RlZmluZWQAAAABCAgIBQAAAAFlAAAACXNlbGxPcmRlcgAAAAlhc3NldFBhaXIAAAAKcHJpY2VBc3NldAkAAAIAAAABAgAAAANlcnIsqB0K` - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - require.NotNil(t, tree) - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - require.NotNil(t, script) - - env := &MockRideEnvironment{ - transactionFunc: testExchangeWithProofsToObject, - } - - rs, err := script.Verify(env) - require.NoError(t, err) - require.Equal(t, rs.Result(), true) -} - -func TestProperty2(t *testing.T) { - t.Run("test simple property", func(t *testing.T) { - n := &PropertyNode{ - Name: "id", - Object: &ReferenceNode{Name: "tx"}, - } - tree := &Tree{ - LibVersion: 3, - AppVersion: scriptApplicationVersion, - Verifier: n, - } - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - require.NotNil(t, script) - - env := &MockRideEnvironment{ - transactionFunc: testExchangeWithProofsToObject, - } - - require.Equal(t, - []byte{ - OpReturn, - OpReturn, - OpRef, 255, 255, - OpRef, 0, 2, - OpProperty, - OpReturn, - }, - script.ByteCode) - _, err = script.run(env, nil) - require.NoError(t, err) - }) - t.Run("test multiple property", func(t *testing.T) { - n := &PropertyNode{ - Name: "assetPair", - Object: &PropertyNode{ - Name: "sellOrder", - Object: &ReferenceNode{Name: "tx"}, - }} - tree := &Tree{ - LibVersion: 3, - AppVersion: scriptApplicationVersion, - Verifier: n, - } - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - require.NotNil(t, script) - - env := &MockRideEnvironment{ - transactionFunc: testExchangeWithProofsToObject, - } - - require.Equal(t, - []byte{ - OpReturn, - OpReturn, - OpRef, 255, 255, - OpRef, 0, 2, - OpProperty, - OpRef, 0, 3, - OpProperty, - OpReturn, - }, - script.ByteCode) - _, err = script.run(env, nil) - require.NoError(t, err) - }) -} - -/* -{-# 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 TestDappMultipleFunctions2(t *testing.T) { - source := "AAIDAAAAAAAAAAwIARIDCgEIEgMKAQgAAAAAAAAAAgAAAAFpAQAAAANhYmMAAAABAAAACHF1ZXN0aW9uCQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACAgAAAAFhAAAAAAAAAAAFBQAAAANuaWwAAAABaQEAAAADY2JhAAAAAQAAAAhxdWVzdGlvbgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAABYQAAAAAAAAAABgUAAAADbmlsAAAAAFEpRso=" - - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - require.NotNil(t, tree) - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - require.NotNil(t, script) - - rs, err := script.Invoke(nil, "abc", []rideType{rideString(""), rideString("")}) - require.NoError(t, err) - - require.Equal(t, true, rs.Result()) - require.Equal(t, - []proto.ScriptAction{ - &proto.DataEntryScriptAction{ - Entry: &proto.IntegerDataEntry{Value: 5, Key: "a"}, - }, - }, []proto.ScriptAction(rs.ScriptActions())) - - rs, err = script.Invoke(nil, "cba", []rideType{rideString(""), rideString("")}) - require.NoError(t, err) - - require.Equal(t, true, rs.Result()) - require.Equal(t, - []proto.ScriptAction{ - &proto.DataEntryScriptAction{ - Entry: &proto.IntegerDataEntry{Value: 6, Key: "a"}, - }, - }, []proto.ScriptAction(rs.ScriptActions())) -} - -/* -{-# 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 TestIfStmt2(t *testing.T) { - source := `BAoBAAAAAmlkAAAAAQAAAAF2AwUAAAABdgQAAAABeAkAAAIAAAABAgAAAAFhAAAAAAAAAAABBAAAAAF4CQAAAgAAAAECAAAAAWIAAAAAAAAAAAIJAAAAAAAAAgAAAAAAAAAAAQkBAAAAAmlkAAAAAQYYAiEb` - state := &MockSmartState{ - NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }, - } - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - checkMessageLengthFunc: func(in1 int) bool { - return true - }, - } - - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - - res, err := script.Verify(env) - require.NoError(t, err) - r, ok := res.(ScriptResult) - require.True(t, ok) - - for _, l := range r.calls { - t.Log(l) - } - - require.Equal(t, true, r.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 TestDapp3(t *testing.T) { - source := `AAIDAAAAAAAAAAkIARIAEgMKAQEAAAAAAAAAAgAAAAFpAQAAAAdkZXBvc2l0AAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAAJaXNEZWZpbmVkAAAAAQgFAAAAA3BtdAAAAAdhc3NldElkCQAAAgAAAAECAAAAIWNhbiBob2xkIHdhdmVzIG9ubHkgYXQgdGhlIG1vbWVudAQAAAAKY3VycmVudEtleQkAAlgAAAABCAgFAAAAAWkAAAAGY2FsbGVyAAAABWJ5dGVzBAAAAA1jdXJyZW50QW1vdW50BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAACmN1cnJlbnRLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAQAAAAJbmV3QW1vdW50CQAAZAAAAAIFAAAADWN1cnJlbnRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACBQAAAApjdXJyZW50S2V5BQAAAAluZXdBbW91bnQFAAAAA25pbAAAAAFpAQAAAAh3aXRoZHJhdwAAAAEAAAAGYW1vdW50BAAAAApjdXJyZW50S2V5CQACWAAAAAEICAUAAAABaQAAAAZjYWxsZXIAAAAFYnl0ZXMEAAAADWN1cnJlbnRBbW91bnQEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAEdGhpcwUAAAAKY3VycmVudEtleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAABAAAAAluZXdBbW91bnQJAABlAAAAAgUAAAANY3VycmVudEFtb3VudAUAAAAGYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAZhbW91bnQJAAACAAAAAQIAAAAeQ2FuJ3Qgd2l0aGRyYXcgbmVnYXRpdmUgYW1vdW50AwkAAGYAAAACAAAAAAAAAAAABQAAAAluZXdBbW91bnQJAAACAAAAAQIAAAASTm90IGVub3VnaCBiYWxhbmNlCQEAAAAMU2NyaXB0UmVzdWx0AAAAAgkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwJAQAAAAtUcmFuc2ZlclNldAAAAAEJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAAZhbW91bnQFAAAABHVuaXQFAAAAA25pbAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V54232jg==` - state := &MockSmartState{ - NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }, - } - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - checkMessageLengthFunc: func(in1 int) bool { - return true - }, - } - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - require.NotNil(t, tree) - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - require.NotNil(t, script) - require.Equal(t, 4, len(script.EntryPoints)) - - rs, err := script.Verify(env) - require.NoError(t, err) - require.NotNil(t, rs) -} - -/* -{-# 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)]) - } - } - -@Verifier(tx) -func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) -*/ -func TestDappVerifier(t *testing.T) { - source := `AAIDAAAAAAAAAAQIARIAAAAAAAAAAAEAAAABaQEAAAAHZGVwb3NpdAAAAAAEAAAAA3BtdAkBAAAAB2V4dHJhY3QAAAABCAUAAAABaQAAAAdwYXltZW50AwkBAAAACWlzRGVmaW5lZAAAAAEIBQAAAANwbXQAAAAHYXNzZXRJZAkAAAIAAAABAgAAACFjYW4gaG9sZCB3YXZlcyBvbmx5IGF0IHRoZSBtb21lbnQEAAAACmN1cnJlbnRLZXkJAAJYAAAAAQgIBQAAAAFpAAAABmNhbGxlcgAAAAVieXRlcwQAAAANY3VycmVudEFtb3VudAQAAAAHJG1hdGNoMAkABBoAAAACBQAAAAR0aGlzBQAAAApjdXJyZW50S2V5AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAAWEFAAAAByRtYXRjaDAFAAAAAWEAAAAAAAAAAAAEAAAACW5ld0Ftb3VudAkAAGQAAAACBQAAAA1jdXJyZW50QW1vdW50CAUAAAADcG10AAAABmFtb3VudAkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAKY3VycmVudEtleQUAAAAJbmV3QW1vdW50BQAAAANuaWwAAAABAAAAAnR4AQAAAAZ2ZXJpZnkAAAAACQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAgFAAAAAnR4AAAAD3NlbmRlclB1YmxpY0tleVRzVhY=` - state := &MockSmartState{ - NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }, - } - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - checkMessageLengthFunc: func(in1 int) bool { - return true - }, - } - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - require.NotNil(t, tree) - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - require.NotNil(t, script) - - rs, err := script.Verify(env) - require.NoError(t, err) - require.NotNil(t, rs) -} - -func TestLetInLet2(t *testing.T) { - //{`let x = {let y = true;y}x`, `BAQAAAABeAQAAAABeQYFAAAAAXkFAAAAAXhCPj2C`, nil, true}, - source := `AwQAAAABeAQAAAABeQAAAAAAAAAABQYFAAAAAXhy1aZr` - state := &MockSmartState{ - NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - return byte_helpers.TransferWithProofs.Transaction, nil - }, - } - env := &MockRideEnvironment{ - transactionFunc: testTransferObject, - stateFunc: func() types.SmartState { - return state - }, - schemeFunc: func() byte { - return 'T' - }, - checkMessageLengthFunc: func(in1 int) bool { - return true - }, - } - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - require.NotNil(t, tree) - - script, err := CompileFlatTree(tree) - require.NoError(t, err) - require.NotNil(t, script) - - rs, err := script.Verify(env) - require.NoError(t, err) - require.NotNil(t, rs) -} - -func TestFlatProperty(t *testing.T) { - n := &PropertyNode{ - Name: "assetPair", - Object: &PropertyNode{ - Name: "sellOrder", - Object: &ReferenceNode{Name: "tx"}, - }} - rs := flatProperty(n) - require.Equal(t, []RNode{ - &RReferenceNode{Name: "tx"}, - &RConst{Value: rideString("sellOrder")}, - &RProperty{}, - &RConst{Value: rideString("assetPair")}, - &RProperty{}, - }, rs) -} diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index dcc003e615..ca8e66ced8 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -3,6 +3,7 @@ package ride import ( "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" + "go.uber.org/zap" ) func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { @@ -20,45 +21,44 @@ func CallVmVerifier(txID string, env RideEnvironment, compiled *Executable) (Rid return compiled.Verify(env) } -func CallVerifier(txID string, env RideEnvironment, tree *Tree) (RideResult, error) { - //r, err := CallVmVerifier(txID, env, tree) - //if err != nil { - // return nil, err - //} - +func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) (RideResult, error) { + r, err := CallVmVerifier(txID, env, exe) + if err != nil { + return nil, err + } r2, err := CallTreeVerifier(env, tree) if err != nil { return nil, err } - /* - if !r.Eq(r2) { - c1 := r.Calls() - c2 := r2.Calls() - max := len(c1) - if len(c2) > len(c1) { - max = len(c2) + + if !r.Eq(r2) { + c1 := r.Calls() + c2 := r2.Calls() + max := len(c1) + if len(c2) > len(c1) { + max = len(c2) + } + for i := 0; i < max; i++ { + //zap.S().Error("R1 != R2: failed to call account script on transaction ") + if i <= len(c1)-1 { + zap.S().Error(i, txID, " ", c1[i]) + } else { + zap.S().Error(i, txID, " ", "") } - for i := 0; i < max; i++ { - //zap.S().Error("R1 != R2: failed to call account script on transaction ") - if i <= len(c1)-1 { - zap.S().Error(i, " ", c1[i]) - } else { - zap.S().Error(i, " ", "") - } - if i <= len(c2)-1 { - zap.S().Error(i, " ", c2[i]) - } else { - zap.S().Error(i, " ", "") - } + if i <= len(c2)-1 { + zap.S().Error(i, txID, " ", c2[i]) + } else { + zap.S().Error(i, txID, " ", "") } - - return nil, errors.New("R1 != R2: failed to call account script on transaction ") } - */ + + return nil, errors.New("R1 != R2: failed to call account script on transaction ") + } + return r2, nil } -func CallTreeFunction(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { +func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { if name == "" { name = "default" } @@ -69,29 +69,39 @@ func CallTreeFunction(env RideEnvironment, tree *Tree, name string, args proto.A return e.evaluate() } -func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - return CallTreeFunction(env, tree, name, args) +func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, name string, args proto.Arguments) (RideResult, error) { + rs1, err := CallTreeFunction(txID, env, tree, name, args) + if err != nil { + return nil, errors.Wrap(err, "call function by tree") + } + rs2, err := CallVmFunction(txID, env, exe, name, args) + if err != nil { + return rs2, errors.Wrap(err, "call function by vm") + } + if !rs1.Eq(rs2) { + c1 := rs1.Calls() + c2 := rs2.Calls() + max := len(c1) + if len(c2) > len(c1) { + max = len(c2) + } + for i := 0; i < max; i++ { + if i <= len(c1)-1 { + zap.S().Error(i, txID, " ", c1[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + if i <= len(c2)-1 { + zap.S().Error(i, txID, " ", c2[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + } + return nil, errors.New("R1 != R2: failed to call account script on transaction ") + } + return rs2, nil } -//func CallFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { -// -// //rs1, err := CallTreeFunction(env, tree, name, args) -// //if err != nil { -// // return nil, errors.Wrap(err, "call function by tree") -// //} -// rs2, err := CallVmFunction(txID, env, tree, name, args) -// if err != nil { -// return rs2, errors.Wrap(err, "call function by vm") -// } -// //if !rs1.Eq(rs2) { -// // zap.S().Errorf("%s, result mismatch", txID) -// // zap.S().Errorf("tree: %+q", rs1) -// // zap.S().Errorf("vm : %+q", rs2) -// // return nil, errors.New(txID + ": result mismatch") -// //} -// return rs2, nil -//} - func CallVmFunction(txID string, env RideEnvironment, e *Executable, name string, args proto.Arguments) (RideResult, error) { if name == "" { name = "default" @@ -103,8 +113,7 @@ func CallVmFunction(txID string, env RideEnvironment, e *Executable, name string if l := len(args); l != int(entry.argn) { return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) } - applyArgs := make([]rideType, 0, len(args)+1) - applyArgs = append(applyArgs, env.invocation()) + applyArgs := make([]rideType, 0, len(args)) for _, arg := range args { a, err := convertArgument(arg) if err != nil { diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 8b7a9ff527..b9518446d6 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -515,7 +515,7 @@ func TestDappCallable(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallTreeFunction(env, tree, "tellme", proto.Arguments{proto.NewStringArgument("abc")}) + res, err := CallTreeFunction("", env, tree, "tellme", proto.Arguments{proto.NewStringArgument("abc")}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -582,7 +582,7 @@ func TestDappDefaultFunc(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "", proto.Arguments{}) + res, err := CallTreeFunction("", env, tree, "", proto.Arguments{}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -646,7 +646,7 @@ func TestDappVerify(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -678,7 +678,7 @@ func TestDappVerifySuccessful(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier("", env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -707,7 +707,7 @@ func TestTransferSet(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100500)}) + res, err := CallTreeFunction("", env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100500)}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -759,7 +759,7 @@ func TestScriptResult(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100)}) + res, err := CallTreeFunction("", env, tree, "tellme", proto.Arguments{proto.NewIntegerArgument(100)}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1139,7 +1139,7 @@ func TestWhaleDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallTreeFunction(env, tree, "inviteuser", arguments) + res, err := CallTreeFunction("", env, tree, "inviteuser", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1265,7 +1265,7 @@ func TestExchangeDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "cancel", arguments) + res, err := CallTreeFunction("", env, tree, "cancel", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1432,7 +1432,7 @@ func TestBankDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallTreeFunction(env, tree, "buyBack", proto.Arguments{}) + res, err := CallTreeFunction("", env, tree, "buyBack", proto.Arguments{}) require.NoError(t, err) _, ok := res.(DAppResult) require.True(t, ok) @@ -1576,7 +1576,7 @@ func TestLigaDApp1(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallTreeFunction(env, tree, "stage2", proto.Arguments{}) + res, err := CallTreeFunction("", env, tree, "stage2", proto.Arguments{}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -1760,7 +1760,7 @@ func TestLigaDApp1(t *testing.T) { }, } - res, err = CallTreeFunction(env, tree, "stage31", args2) + res, err = CallTreeFunction("", env, tree, "stage31", args2) require.NoError(t, err) r, ok = res.(DAppResult) require.True(t, ok) @@ -1889,7 +1889,7 @@ func TestTestingDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "main", arguments) + res, err := CallTreeFunction("", env, tree, "main", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2002,7 +2002,7 @@ func TestDropElementDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallTreeFunction(env, tree, "dropElementInArray", arguments) + res, err := CallTreeFunction("", env, tree, "dropElementInArray", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2116,7 +2116,7 @@ func TestMathDApp(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallTreeFunction(env, tree, "coxRossRubinsteinCall", arguments) + res, err := CallTreeFunction("", env, tree, "coxRossRubinsteinCall", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2242,7 +2242,7 @@ func TestDAppWithInvalidAddress(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "deposit", arguments) + res, err := CallTreeFunction("", env, tree, "deposit", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2371,7 +2371,7 @@ func Test8Ball(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "tellme", arguments) + res, err := CallTreeFunction("", env, tree, "tellme", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2479,7 +2479,7 @@ func TestIntegerEntry(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - _, err = CallFunction("", env, tree, "tellme", arguments) + _, err = CallTreeFunction("", env, tree, "tellme", arguments) assert.Error(t, err) } @@ -2593,7 +2593,7 @@ func TestDAppWithFullIssue(t *testing.T) { return rideBytes(id) }, } - res, err := CallTreeFunction(env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) + res, err := CallTreeFunction("", env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2619,7 +2619,7 @@ func TestDAppWithSimpleIssue(t *testing.T) { return rideBytes(id) }, } - res, err := CallTreeFunction(env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) + res, err := CallTreeFunction("", env, tree, "issue", proto.Arguments{&proto.StringArgument{Value: "xxx"}}) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2721,7 +2721,7 @@ func TestBadType(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "initDraw", arguments) + res, err := CallTreeFunction("", env, tree, "initDraw", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -2883,7 +2883,7 @@ func TestNoDeclaration(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallTreeFunction(env, tree, "settle", arguments) + res, err := CallTreeFunction("", env, tree, "settle", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -3070,7 +3070,7 @@ func TestZeroReissue(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "replenishment", arguments) + res, err := CallTreeFunction("", env, tree, "replenishment", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -3290,7 +3290,7 @@ func TestStageNet2(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction("", env, tree, "purchaseToken", arguments) + res, err := CallTreeFunction("", env, tree, "purchaseToken", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) @@ -3374,7 +3374,7 @@ func TestRecipientAddressToString(t *testing.T) { checkMessageLengthFunc: v3check, } - res, err := CallVerifier("", env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index facec89318..8b4fbb224f 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -9,7 +9,6 @@ import ( "github.com/wavesplatform/gowaves/pkg/ride" "github.com/wavesplatform/gowaves/pkg/settings" "github.com/wavesplatform/gowaves/pkg/types" - "go.uber.org/zap" ) type scriptCaller struct { @@ -43,8 +42,11 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return err } - //tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) - tree, err := a.stor.scriptsStorage.newestBytecodeByAddr(sender, !initialisation) + tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) + if err != nil { + return errors.Wrap(err, "failed to retrieve account script") + } + exe, err := a.stor.scriptsStorage.newestBytecodeByAddr(sender, !initialisation) if err != nil { return errors.Wrap(err, "failed to retrieve account script") } @@ -54,12 +56,12 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn } env.SetThisFromAddress(sender) env.SetLastBlock(lastBlockInfo) - env.ChooseSizeCheck(tree.LibVersion) + env.ChooseSizeCheck(exe.LibVersion) err = env.SetTransactionFromOrder(order) if err != nil { return errors.Wrap(err, "failed to convert order") } - r, err := ride.CallVmVerifier("scriptCaller callAccountScriptWithOrder", env, tree) + r, err := ride.CallVerifier("scriptCaller callAccountScriptWithOrder", env, tree, exe) if err != nil { return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) } @@ -92,8 +94,11 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return err } - tree, err := a.stor.scriptsStorage.newestBytecodeByAddr(senderAddr, !initialisation) - //tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) + tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) + if err != nil { + return err + } + exe, err := a.stor.scriptsStorage.newestBytecodeByAddr(senderAddr, !initialisation) if err != nil { return err } @@ -109,7 +114,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } //zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) - r, err := ride.CallVmVerifier(txID, env, tree) + r, err := ride.CallVerifier(txID, env, tree, exe) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } @@ -142,12 +147,16 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn } func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID crypto.Digest, lastBlockInfo *proto.BlockInfo, initialisation bool, acceptFailed bool) (ride.RideResult, error) { - tree, err := a.stor.scriptsStorage.newestBytecodeByAsset(assetID, !initialisation) + tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !initialisation) + if err != nil { + return nil, err + } + exe, err := a.stor.scriptsStorage.newestBytecodeByAsset(assetID, !initialisation) if err != nil { return nil, err } - env.ChooseSizeCheck(tree.LibVersion) - switch tree.LibVersion { + env.ChooseSizeCheck(exe.LibVersion) + switch exe.LibVersion { case 4: assetInfo, err := a.state.NewestFullAssetInfo(assetID) if err != nil { @@ -162,7 +171,7 @@ func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID cryp env.SetThisFromAssetInfo(assetInfo) } env.SetLastBlock(lastBlockInfo) - r, err := ride.CallVmVerifier("scriptCaller callAssetScriptCommon", env, tree) + r, err := ride.CallVerifier("scriptCaller callAssetScriptCommon", env, tree, exe) if err != nil { return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) } @@ -222,23 +231,24 @@ func (a *scriptCaller) invokeFunction(exe *ride.Executable, tx *proto.InvokeScri } env.ChooseSizeCheck(exe.LibVersion) - for i, f := range tree.Declarations { - rs := ride.Decompiler(f) - zap.S().Error(i, " == ", rs) - - } - for i, f := range tree.Functions { - rs := ride.Decompiler(f) - zap.S().Error(i, " == ", rs) - } - - zap.S().Error("verifier: == ", tree.Verifier) - for i, v := range tx.FunctionCall.Arguments { - zap.S().Errorf("%d argument %+v, %T", i, v, v) - } + //for i, f := range tree.Declarations { + // rs := ride.Decompiler(f) + // zap.S().Error(i, " == ", rs) + // + //} + //for i, f := range tree.Functions { + // rs := ride.Decompiler(f) + // zap.S().Error(i, " == ", rs) + //} + // + //zap.S().Error("verifier: == ", tree.Verifier) + //for i, v := range tx.FunctionCall.Arguments { + // zap.S().Errorf("%d argument %+v, %T", i, v, v) + //} - r, err := ride.CallVmFunction(txID, env, exe, tx.FunctionCall.Name, tx.FunctionCall.Arguments) - //r, err := ride.CallFunction(txID, env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + r, err := ride.CallFunction(txID, env, exe, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + //r, err := ride.CallVmFunction(txID, env, exe, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + //r, err := ride.CallTreeFunction(txID, env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } From 8a2b1cdfbb6000defe1101b6c6b5669ad2f140eb Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 4 Feb 2021 17:08:44 +0300 Subject: [PATCH 32/55] Enabled cache. --- pkg/ride/compiler2_test.go | 16 +++--- pkg/ride/compiler_state.go | 15 +++++ pkg/ride/tree_evaluation.go | 107 ++++++++++++++++++------------------ pkg/ride/vm.go | 14 +++++ pkg/state/scripts_cache.go | 2 - 5 files changed, 90 insertions(+), 64 deletions(-) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 003d53a570..89044a72e3 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -141,10 +141,10 @@ func TestCallExternal(t *testing.T) { []byte{ OpReturn, OpReturn, - OpRef, 0, 3, - OpCache, 0, 3, - OpRef, 0, 4, - OpCache, 0, 4, + OpRef, 0, 1, + OpCache, 0, 1, + OpRef, 0, 1, + OpCache, 0, 1, OpExternalCall, 0, 3, 0, 2, OpReturn, }, @@ -816,7 +816,7 @@ func TestProperty(t *testing.T) { OpReturn, OpReturn, OpRef, 255, 255, - OpRef, 0, 2, + OpRef, 0, 202, OpProperty, OpReturn, OpReturn, @@ -850,14 +850,14 @@ func TestProperty(t *testing.T) { []byte{ OpReturn, OpReturn, - OpRef, 0, 3, - OpRef, 0, 4, + OpRef, 0, 203, + OpRef, 0, 204, OpProperty, OpReturn, OpReturn, OpRef, 255, 255, - OpRef, 0, 5, + OpRef, 0, 205, OpProperty, OpReturn, OpReturn, diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 545b393618..1e86cec039 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -33,6 +33,9 @@ type uniqid struct { } func (a *uniqid) next() uint16 { + if a.id < 200 { + a.id = 200 + } a.id++ return a.id } @@ -66,6 +69,18 @@ func (a *params) addPredefined(name string, id uniqueid, fn uint16) { } func (a *params) constant(value rideType) constantDeferred { + switch v := value.(type) { + case rideInt: + if v >= 0 && v <= 100 { + return NewConstantDeferred(uniqueid(v)) + } + case rideBoolean: + if v { + return NewConstantDeferred(101) + } else { + return NewConstantDeferred(102) + } + } n := a.u.next() a.c.set(n, value, 0, 0, true, fmt.Sprintf("constant %q", value)) return NewConstantDeferred(n) diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index ca8e66ced8..9164f18fd2 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -3,7 +3,6 @@ package ride import ( "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" - "go.uber.org/zap" ) func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { @@ -26,36 +25,36 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) if err != nil { return nil, err } - r2, err := CallTreeVerifier(env, tree) - if err != nil { - return nil, err - } - - if !r.Eq(r2) { - c1 := r.Calls() - c2 := r2.Calls() - max := len(c1) - if len(c2) > len(c1) { - max = len(c2) - } - for i := 0; i < max; i++ { - //zap.S().Error("R1 != R2: failed to call account script on transaction ") - if i <= len(c1)-1 { - zap.S().Error(i, txID, " ", c1[i]) - } else { - zap.S().Error(i, txID, " ", "") - } - if i <= len(c2)-1 { - zap.S().Error(i, txID, " ", c2[i]) - } else { - zap.S().Error(i, txID, " ", "") - } - } + //r2, err := CallTreeVerifier(env, tree) + //if err != nil { + // return nil, err + //} - return nil, errors.New("R1 != R2: failed to call account script on transaction ") - } + //if !r.Eq(r2) { + // c1 := r.Calls() + // c2 := r2.Calls() + // max := len(c1) + // if len(c2) > len(c1) { + // max = len(c2) + // } + // for i := 0; i < max; i++ { + // //zap.S().Error("R1 != R2: failed to call account script on transaction ") + // if i <= len(c1)-1 { + // zap.S().Error(i, txID, " ", c1[i]) + // } else { + // zap.S().Error(i, txID, " ", "") + // } + // if i <= len(c2)-1 { + // zap.S().Error(i, txID, " ", c2[i]) + // } else { + // zap.S().Error(i, txID, " ", "") + // } + // } + // + // return nil, errors.New("R1 != R2: failed to call account script on transaction ") + //} - return r2, nil + return r, nil } func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { @@ -70,35 +69,35 @@ func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, } func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - rs1, err := CallTreeFunction(txID, env, tree, name, args) - if err != nil { - return nil, errors.Wrap(err, "call function by tree") - } + //rs1, err := CallTreeFunction(txID, env, tree, name, args) + //if err != nil { + // return nil, errors.Wrap(err, "call function by tree") + //} rs2, err := CallVmFunction(txID, env, exe, name, args) if err != nil { return rs2, errors.Wrap(err, "call function by vm") } - if !rs1.Eq(rs2) { - c1 := rs1.Calls() - c2 := rs2.Calls() - max := len(c1) - if len(c2) > len(c1) { - max = len(c2) - } - for i := 0; i < max; i++ { - if i <= len(c1)-1 { - zap.S().Error(i, txID, " ", c1[i]) - } else { - zap.S().Error(i, txID, " ", "") - } - if i <= len(c2)-1 { - zap.S().Error(i, txID, " ", c2[i]) - } else { - zap.S().Error(i, txID, " ", "") - } - } - return nil, errors.New("R1 != R2: failed to call account script on transaction ") - } + //if !rs1.Eq(rs2) { + // c1 := rs1.Calls() + // c2 := rs2.Calls() + // max := len(c1) + // if len(c2) > len(c1) { + // max = len(c2) + // } + // for i := 0; i < max; i++ { + // if i <= len(c1)-1 { + // zap.S().Error(i, txID, " ", c1[i]) + // } else { + // zap.S().Error(i, txID, " ", "") + // } + // if i <= len(c2)-1 { + // zap.S().Error(i, txID, " ", c2[i]) + // } else { + // zap.S().Error(i, txID, " ", "") + // } + // } + // return nil, errors.New("R1 != R2: failed to call account script on transaction ") + //} return rs2, nil } diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index ad84d3eea0..46b2dccb85 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -142,6 +142,9 @@ func (m *vm) run() (rideType, error) { m.ref[to] = m.ref[from] case OpCache: refID := m.uint16() + if refID < 200 { + continue + } value, err := m.pop() if err != nil { return nil, errors.Wrap(err, "no value to cache") @@ -164,6 +167,17 @@ func (m *vm) run() (rideType, error) { case OpRef: refID := m.uint16() + switch { + case refID <= 100: + m.push(rideInt(refID)) + continue + case refID == 101: + m.push(rideBoolean(true)) + continue + case refID == 102: + m.push(rideBoolean(false)) + continue + } point, ok := m.ref[refID] if !ok { return nil, errors.Errorf("reference %d not found", refID) diff --git a/pkg/state/scripts_cache.go b/pkg/state/scripts_cache.go index 77858d317e..0275fc91d4 100644 --- a/pkg/state/scripts_cache.go +++ b/pkg/state/scripts_cache.go @@ -86,14 +86,12 @@ func (l *lru) get(key []byte) (value *ride.Executable, has bool) { if !has { return } - panic("unreachable!!") l.cut(e) l.setNewest(e) return e.value, true } func (l *lru) set(key []byte, value *ride.Executable, bytes uint64) (existed bool) { - return false keyStr := string(key) e, has := l.m[keyStr] if has { From 78afd8598a851d37222a998ad72a61bcb8977985 Mon Sep 17 00:00:00 2001 From: Frozen Date: Thu, 4 Feb 2021 23:10:18 +0300 Subject: [PATCH 33/55] Merged master. --- pkg/ride/constants.go | 186 +++++++++---------------------- pkg/ride/tree_evaluation_test.go | 4 +- pkg/state/invoke_applier.go | 10 +- pkg/state/script_caller.go | 34 +++--- pkg/state/scripts_storage.go | 1 + 5 files changed, 80 insertions(+), 155 deletions(-) diff --git a/pkg/ride/constants.go b/pkg/ride/constants.go index 095c9a6953..16e1e90842 100644 --- a/pkg/ride/constants.go +++ b/pkg/ride/constants.go @@ -90,82 +90,6 @@ func checkConstantV4(name string) (uint16, bool) { return 0, false } -func newSha256(RideEnvironment) rideType { - return rideNamedType{name: "Sha256"} -} - -func newHalfDown(RideEnvironment) rideType { - return rideNamedType{name: "HalfDown"} -} - -func createHalfDown(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfDown"}, nil -} - -func newMd5(RideEnvironment) rideType { - return rideNamedType{name: "Md5"} -} - -func createMd5(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Md5"}, nil -} - -func newSha1(RideEnvironment) rideType { - return rideNamedType{name: "Sha1"} -} - -func createSha1(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha1"}, nil -} - -func newSha3384(RideEnvironment) rideType { - return rideNamedType{name: "Sha3384"} -} - -func createSha3384(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3384"}, nil -} - -func newSha1(RideEnvironment) rideType { - return rideNamedType{name: "Sha1"} -} - -func createSha1(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha1"}, nil -} - -func newSell(RideEnvironment) rideType { - return rideNamedType{name: "Sell"} -} - -func createSell(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sell"}, nil -} - -func newCeiling(RideEnvironment) rideType { - return rideNamedType{name: "Ceiling"} -} - -func createCeiling(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Ceiling"}, nil -} - -func newFloor(RideEnvironment) rideType { - return rideNamedType{name: "Floor"} -} - -func createFloor(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Floor"}, nil -} - -func newSell(RideEnvironment) rideType { - return rideNamedType{name: "Sell"} -} - -func createSell(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sell"}, nil -} - func newFloor(RideEnvironment) rideType { return rideNamedType{name: "Floor"} } @@ -174,14 +98,6 @@ func createFloor(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Floor"}, nil } -func newDown(RideEnvironment) rideType { - return rideNamedType{name: "Down"} -} - -func createDown(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Down"}, nil -} - func newUp(RideEnvironment) rideType { return rideNamedType{name: "Up"} } @@ -190,17 +106,22 @@ func createUp(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Up"}, nil } -func newHalfUp(RideEnvironment) rideType { - return rideNamedType{name: "HalfUp"} +func newSha256(RideEnvironment) rideType { + return rideNamedType{name: "Sha256"} } -func createHalfUp(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfUp"}, nil +func createSha256(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha256"}, nil } -func newMd5(RideEnvironment) rideType { - return rideNamedType{name: "Md5"} +func newSell(RideEnvironment) rideType { + return rideNamedType{name: "Sell"} +} + +func createSell(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sell"}, nil } + func newNoAlg(RideEnvironment) rideType { return rideNamedType{name: "NoAlg"} } @@ -209,23 +130,28 @@ func createNoAlg(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "NoAlg"}, nil } -func newSha512(RideEnvironment) rideType { - return rideNamedType{name: "Sha512"} +func newMd5(RideEnvironment) rideType { + return rideNamedType{name: "Md5"} } func createMd5(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Md5"}, nil } + +func newSha512(RideEnvironment) rideType { + return rideNamedType{name: "Sha512"} +} + func createSha512(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Sha512"}, nil } -func newSha224(RideEnvironment) rideType { - return rideNamedType{name: "Sha224"} +func newSha3384(RideEnvironment) rideType { + return rideNamedType{name: "Sha3384"} } -func createSha224(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha224"}, nil +func createSha3384(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3384"}, nil } func newSha3512(RideEnvironment) rideType { @@ -236,24 +162,12 @@ func createSha3512(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Sha3512"}, nil } -func newHalfDown(RideEnvironment) rideType { - return rideNamedType{name: "HalfDown"} -} - -func createHalfDown(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfDown"}, nil -} - -func newBuy(RideEnvironment) rideType { - return rideNamedType{name: "Buy"} -} - -func newCeiling(RideEnvironment) rideType { - return rideNamedType{name: "Ceiling"} +func newSha3256(RideEnvironment) rideType { + return rideNamedType{name: "Sha3256"} } -func createCeiling(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Ceiling"}, nil +func createSha3256(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha3256"}, nil } func newBuy(RideEnvironment) rideType { @@ -264,12 +178,12 @@ func createBuy(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Buy"}, nil } -func newSha3256(RideEnvironment) rideType { - return rideNamedType{name: "Sha3256"} +func newDown(RideEnvironment) rideType { + return rideNamedType{name: "Down"} } -func createSha3256(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3256"}, nil +func createDown(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Down"}, nil } func newHalfUp(RideEnvironment) rideType { @@ -280,6 +194,22 @@ func createHalfUp(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "HalfUp"}, nil } +func newHalfDown(RideEnvironment) rideType { + return rideNamedType{name: "HalfDown"} +} + +func createHalfDown(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfDown"}, nil +} + +func newSha1(RideEnvironment) rideType { + return rideNamedType{name: "Sha1"} +} + +func createSha1(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Sha1"}, nil +} + func newSha224(RideEnvironment) rideType { return rideNamedType{name: "Sha224"} } @@ -288,25 +218,22 @@ func createSha224(env RideEnvironment, args ...rideType) (rideType, error) { return rideNamedType{name: "Sha224"}, nil } -func newSha256(RideEnvironment) rideType { - return rideNamedType{name: "Sha256"} +func newCeiling(RideEnvironment) rideType { + return rideNamedType{name: "Ceiling"} } -func createSha256(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha256"}, nil +func createCeiling(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "Ceiling"}, nil } -func newSha384(RideEnvironment) rideType { - return rideNamedType{name: "Sha384"} +func newHalfEven(RideEnvironment) rideType { + return rideNamedType{name: "HalfEven"} } -func createSha384(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha384"}, nil +func createHalfEven(env RideEnvironment, args ...rideType) (rideType, error) { + return rideNamedType{name: "HalfEven"}, nil } -func newHalfEven(RideEnvironment) rideType { - return rideNamedType{name: "HalfEven"} -} func newSha384(RideEnvironment) rideType { return rideNamedType{name: "Sha384"} } @@ -320,8 +247,5 @@ func newSha3224(RideEnvironment) rideType { } func createSha3224(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "Sha3224"}, nil - } -func createHalfEven(env RideEnvironment, args ...rideType) (rideType, error) { - return rideNamedType{name: "HalfEven"}, nil + return rideNamedType{name: "Sha3224"}, nil } diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 0a01d6da98..3f4b344cdc 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -3424,7 +3424,7 @@ func TestScriptPaymentPublicKey(t *testing.T) { require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallVerifier(env, tree) + res, err := CallTreeVerifier(env, tree) require.NoError(t, err) r, ok := res.(ScriptResult) require.True(t, ok) @@ -3488,7 +3488,7 @@ func TestInvalidAssetInTransferScriptAction(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) assert.NotNil(t, tree) - res, err := CallFunction(env, tree, "swapRKMTToWAVES", arguments) + res, err := CallTreeFunction("", env, tree, "swapRKMTToWAVES", arguments) require.NoError(t, err) r, ok := res.(DAppResult) require.True(t, ok) diff --git a/pkg/state/invoke_applier.go b/pkg/state/invoke_applier.go index 610b09bea5..9f369815af 100644 --- a/pkg/state/invoke_applier.go +++ b/pkg/state/invoke_applier.go @@ -527,10 +527,10 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf if err != nil { return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) } - tree, err := ia.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !info.initialisation) - if err != nil { - return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) - } + //tree, err := ia.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !info.initialisation) + //if err != nil { + // return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) + //} scriptPK, err := ia.stor.scriptsStorage.newestScriptPKByAddr(*scriptAddr, !info.initialisation) if err != nil { return nil, errors.Wrapf(err, "failed to get script's public key on address '%s'", scriptAddr.String()) @@ -559,7 +559,7 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf return nil, err } // Call script function. - ok, scriptActions, err := ia.sc.invokeFunction(exe, tx, info.blockInfo, *scriptAddr, info.initialisation, tree) + ok, scriptActions, err := ia.sc.invokeFunction(exe, tx, info.blockInfo, *scriptAddr, info.initialisation, nil) if !ok { // When ok is false, it means that we could not even start invocation. // We just return error in such case. diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index 8b4fbb224f..c4c49de2f7 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -42,10 +42,10 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return err } - tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) - if err != nil { - return errors.Wrap(err, "failed to retrieve account script") - } + //tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) + //if err != nil { + // return errors.Wrap(err, "failed to retrieve account script") + //} exe, err := a.stor.scriptsStorage.newestBytecodeByAddr(sender, !initialisation) if err != nil { return errors.Wrap(err, "failed to retrieve account script") @@ -61,7 +61,7 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return errors.Wrap(err, "failed to convert order") } - r, err := ride.CallVerifier("scriptCaller callAccountScriptWithOrder", env, tree, exe) + r, err := ride.CallVerifier("scriptCaller callAccountScriptWithOrder", env, nil, exe) if err != nil { return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) } @@ -94,10 +94,10 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return err } - tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) - if err != nil { - return err - } + //tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) + //if err != nil { + // return err + //} exe, err := a.stor.scriptsStorage.newestBytecodeByAddr(senderAddr, !initialisation) if err != nil { return err @@ -114,7 +114,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } //zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) - r, err := ride.CallVerifier(txID, env, tree, exe) + r, err := ride.CallVerifier(txID, env, nil, exe) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } @@ -147,10 +147,10 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn } func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID crypto.Digest, lastBlockInfo *proto.BlockInfo, initialisation bool, acceptFailed bool) (ride.RideResult, error) { - tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !initialisation) - if err != nil { - return nil, err - } + //tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !initialisation) + //if err != nil { + // return nil, err + //} exe, err := a.stor.scriptsStorage.newestBytecodeByAsset(assetID, !initialisation) if err != nil { return nil, err @@ -171,7 +171,7 @@ func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID cryp env.SetThisFromAssetInfo(assetInfo) } env.SetLastBlock(lastBlockInfo) - r, err := ride.CallVerifier("scriptCaller callAssetScriptCommon", env, tree, exe) + r, err := ride.CallVerifier("scriptCaller callAssetScriptCommon", env, nil, exe) if err != nil { return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) } @@ -225,7 +225,7 @@ func (a *scriptCaller) invokeFunction(exe *ride.Executable, tx *proto.InvokeScri if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } - err = env.SetInvoke(tx, tree.LibVersion) + err = env.SetInvoke(tx, exe.LibVersion) if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } @@ -246,7 +246,7 @@ func (a *scriptCaller) invokeFunction(exe *ride.Executable, tx *proto.InvokeScri // zap.S().Errorf("%d argument %+v, %T", i, v, v) //} - r, err := ride.CallFunction(txID, env, exe, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + r, err := ride.CallFunction(txID, env, exe, nil, tx.FunctionCall.Name, tx.FunctionCall.Arguments) //r, err := ride.CallVmFunction(txID, env, exe, tx.FunctionCall.Name, tx.FunctionCall.Arguments) //r, err := ride.CallTreeFunction(txID, env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) if err != nil { diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 2491eb60a4..3a62b350c7 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -478,6 +478,7 @@ func (ss *scriptsStorage) accountHasScript(addr proto.Address, filter bool) (boo } func (ss *scriptsStorage) newestScriptByAddr(addr proto.Address, filter bool) (*ride.Tree, error) { + panic("unreacheable!") key := accountScriptKey{addr} keyBytes := key.bytes() tree, err := ss.newestScriptAstByKey(keyBytes, filter) From ff8c9598cf1f0aa5f4f8af0894546c8d63591d06 Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 5 Feb 2021 17:32:14 +0300 Subject: [PATCH 34/55] Switchable bloom filter. --- cmd/node/node.go | 5 ++++ pkg/keyvalue/bloom_filter.go | 38 ++++++++++++++++++++++++------- pkg/keyvalue/bloom_filter_stub.go | 29 +++++++++++++++++++++++ pkg/keyvalue/leveldb.go | 4 ++-- 4 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 pkg/keyvalue/bloom_filter_stub.go diff --git a/cmd/node/node.go b/cmd/node/node.go index c3e452c0f0..7f7e013da6 100644 --- a/cmd/node/node.go +++ b/cmd/node/node.go @@ -65,6 +65,7 @@ var ( bindAddress = flag.String("bind-address", "", "Bind address for incoming connections. If empty, will be same as declared address") disableOutgoingConnections = flag.Bool("no-connections", false, "Disable outgoing network connections to peers. Default value is false.") minerVoteFeatures = flag.String("vote", "", "Miner vote features") + bloomFilter = flag.Bool("bloom", true, "Enable/Disable bloom filter. Less memory usage, but decrease performance. Usage: -bloom=false") reward = flag.String("reward", "", "Miner reward: for example 600000000") outdatePeriod = flag.String("outdate", "4h", "Interval after last block then generation is allowed. Example 1d4h30m") walletPath = flag.String("wallet-path", "", "Path to wallet, or ~/.waves by default.") @@ -118,6 +119,7 @@ func debugCommandLineParameters() { zap.S().Debugf("wallet-password: %s", *walletPassword) zap.S().Debugf("limit-connections: %s", *limitConnectionsS) zap.S().Debugf("profiler: %v", *profiler) + zap.S().Debugf("bloom: %v", *bloomFilter) } func main() { @@ -246,6 +248,9 @@ func main() { params.ProvideExtendedApi = *serveExtendedApi params.BuildStateHashes = *buildStateHashes params.Time = ntptm + if !*bloomFilter { + params.DbParams.BloomFilterParams.Disable = true + } st, err := state.NewState(path, params, cfg) if err != nil { zap.S().Error(err) diff --git a/pkg/keyvalue/bloom_filter.go b/pkg/keyvalue/bloom_filter.go index 8f905519df..ca5e48cad7 100644 --- a/pkg/keyvalue/bloom_filter.go +++ b/pkg/keyvalue/bloom_filter.go @@ -14,6 +14,13 @@ import ( "go.uber.org/zap" ) +type BloomFilter interface { + notInTheSet(data []byte) (bool, error) + add(data []byte) error + Params() BloomFilterParams + io.WriterTo +} + type BloomFilterParams struct { // N is how many items will be added to the filter. N int @@ -21,6 +28,8 @@ type BloomFilterParams struct { FalsePositiveProbability float64 // Bloom store. Store store + // Disable bloom filter. + Disable bool } func NewBloomFilterParams(N int, FalsePositiveProbability float64, store store) BloomFilterParams { @@ -40,11 +49,18 @@ func (bf *bloomFilter) WriteTo(w io.Writer) (n int64, err error) { return bf.filter.WriteTo(w) } +func (bf bloomFilter) Params() BloomFilterParams { + return bf.params +} + func (bf *bloomFilter) ReadFrom(r io.Reader) (n int64, err error) { return bf.filter.ReadFrom(r) } -func newBloomFilter(params BloomFilterParams) (*bloomFilter, error) { +func newBloomFilter(params BloomFilterParams) (BloomFilter, error) { + if params.Disable { + return NewBloomFilterStub(params), nil + } bf, err := bloomfilter.NewOptimal(uint64(params.N), params.FalsePositiveProbability) if err != nil { return nil, err @@ -52,7 +68,10 @@ func newBloomFilter(params BloomFilterParams) (*bloomFilter, error) { return &bloomFilter{filter: bf, params: params}, nil } -func newBloomFilterFromStore(params BloomFilterParams) (*bloomFilter, error) { +func newBloomFilterFromStore(params BloomFilterParams) (BloomFilter, error) { + if params.Disable { + return NewBloomFilterStub(params), nil + } f, err := bloomfilter.NewOptimal(uint64(params.N), params.FalsePositiveProbability) if err != nil { return nil, err @@ -71,9 +90,12 @@ func newBloomFilterFromStore(params BloomFilterParams) (*bloomFilter, error) { return bf, nil } -func storeBloomFilter(a *bloomFilter) error { +func storeBloomFilter(a BloomFilter) error { debug.FreeOSMemory() - return a.params.Store.save(a.filter) + if a.Params().Store != nil { + return a.Params().Store.save(a) + } + return nil } func (bf *bloomFilter) add(data []byte) error { @@ -94,7 +116,7 @@ func (bf *bloomFilter) notInTheSet(data []byte) (bool, error) { } type store interface { - save(*bloomfilter.Filter) error + save(to io.WriterTo) error load() ([]byte, error) WithPath(string) } @@ -104,7 +126,7 @@ type NoOpStore struct { func (NoOpStore) WithPath(string) {} -func (a NoOpStore) save(*bloomfilter.Filter) error { +func (a NoOpStore) save(to io.WriterTo) error { return nil } @@ -124,7 +146,7 @@ func (a *storeImpl) tmpFileName() string { return a.path + "tmp" } -func (a *storeImpl) saveData(f *bloomfilter.Filter) error { +func (a *storeImpl) saveData(f io.WriterTo) error { file, err := os.OpenFile(a.tmpFileName(), os.O_RDWR|os.O_CREATE, 0644) if err != nil { return err @@ -160,7 +182,7 @@ func (a *storeImpl) saveData(f *bloomfilter.Filter) error { return nil } -func (a *storeImpl) save(f *bloomfilter.Filter) error { +func (a *storeImpl) save(f io.WriterTo) error { if err := a.saveData(f); err != nil { return err } diff --git a/pkg/keyvalue/bloom_filter_stub.go b/pkg/keyvalue/bloom_filter_stub.go new file mode 100644 index 0000000000..bd349dc950 --- /dev/null +++ b/pkg/keyvalue/bloom_filter_stub.go @@ -0,0 +1,29 @@ +package keyvalue + +import "io" + +type bloomFilterStub struct { + params BloomFilterParams +} + +func NewBloomFilterStub(params BloomFilterParams) bloomFilterStub { + return bloomFilterStub{ + params: params, + } +} + +func (bloomFilterStub) notInTheSet([]byte) (bool, error) { + return false, nil +} + +func (a bloomFilterStub) Params() BloomFilterParams { + return a.params +} + +func (a bloomFilterStub) WriteTo(to io.Writer) (int64, error) { + return 0, nil +} + +func (a bloomFilterStub) add([]byte) error { + return nil +} diff --git a/pkg/keyvalue/leveldb.go b/pkg/keyvalue/leveldb.go index 90506a48af..8348c28184 100644 --- a/pkg/keyvalue/leveldb.go +++ b/pkg/keyvalue/leveldb.go @@ -40,7 +40,7 @@ func (b *batch) Put(key, val []byte) { b.mu.Unlock() } -func (b *batch) addToFilter(filter *bloomFilter) error { +func (b *batch) addToFilter(filter BloomFilter) error { b.mu.Lock() for _, pair := range b.pairs { if !pair.deletion { @@ -90,7 +90,7 @@ func (b *batch) Reset() { type KeyVal struct { db *leveldb.DB - filter *bloomFilter + filter BloomFilter cache *freecache.Cache mu *sync.RWMutex } From 60410b40e2538905899ad9398dd0de8adb438459 Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 5 Feb 2021 17:41:19 +0300 Subject: [PATCH 35/55] Fix tests. --- pkg/keyvalue/bloom_filter_test.go | 2 +- pkg/keyvalue/leveldb_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/keyvalue/bloom_filter_test.go b/pkg/keyvalue/bloom_filter_test.go index f511498bfc..05276f076f 100644 --- a/pkg/keyvalue/bloom_filter_test.go +++ b/pkg/keyvalue/bloom_filter_test.go @@ -18,7 +18,7 @@ const ( ) func TestBloomFilter(t *testing.T) { - filter, err := newBloomFilter(BloomFilterParams{n, falsePositiveProbability, nil}) + filter, err := newBloomFilter(BloomFilterParams{n, falsePositiveProbability, nil, false}) assert.NoError(t, err, "newBloomFilter() failed") for i := 0; i < n; i++ { data := make([]byte, 100) diff --git a/pkg/keyvalue/leveldb_test.go b/pkg/keyvalue/leveldb_test.go index 97616f8be7..9e18fa9d51 100644 --- a/pkg/keyvalue/leveldb_test.go +++ b/pkg/keyvalue/leveldb_test.go @@ -19,7 +19,7 @@ func TestKeyVal(t *testing.T) { dbDir, err := ioutil.TempDir(os.TempDir(), "dbDir0") params := KeyValParams{ CacheParams: CacheParams{cacheSize}, - BloomFilterParams: BloomFilterParams{n, falsePositiveProbability, NoOpStore{}}, + BloomFilterParams: BloomFilterParams{n, falsePositiveProbability, NoOpStore{}, false}, WriteBuffer: writeBuffer, CompactionTableSize: sstableSize, CompactionTotalSize: compactionTotalSize, From b70c14bab8aa24bc9567cd592636960d3a708c32 Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 9 Feb 2021 15:30:51 +0300 Subject: [PATCH 36/55] Code clean up and returned back debug info. --- pkg/ride/compiler.go | 43 +- pkg/ride/compiler2_test.go | 4 +- pkg/ride/compiler_assigment.go | 1 - pkg/ride/compiler_call_system.go | 2 +- pkg/ride/compiler_call_user.go | 9 +- pkg/ride/compiler_conditional.go | 3 - pkg/ride/compiler_helpers.go | 64 +-- pkg/ride/compiler_main.go | 1 - pkg/ride/compiler_state.go | 6 - pkg/ride/deserializer.go | 52 ++ pkg/ride/deserializer_test.go | 76 ++- pkg/ride/evaluation_result.go | 28 + pkg/ride/executable.go | 19 + pkg/ride/program.go | 4 + pkg/ride/reverse_tree.go | 710 ------------------------ pkg/ride/runtime.go | 47 +- pkg/ride/serializer.go | 46 +- pkg/ride/tree_evaluation.go | 105 ++-- pkg/ride/tree_evaluator.go | 9 +- pkg/state/common_test.go | 2 +- pkg/state/fee_validation_test.go | 4 +- pkg/state/invoke_applier.go | 11 +- pkg/state/invoke_applier_test.go | 2 +- pkg/state/script_caller.go | 34 +- pkg/state/scripts_storage.go | 26 +- pkg/state/scripts_storage_test.go | 8 +- pkg/state/transaction_checker_test.go | 4 +- pkg/state/transaction_performer_test.go | 2 +- 28 files changed, 370 insertions(+), 952 deletions(-) create mode 100644 pkg/ride/evaluation_result.go diff --git a/pkg/ride/compiler.go b/pkg/ride/compiler.go index 118ffc38b8..7654bb75b7 100644 --- a/pkg/ride/compiler.go +++ b/pkg/ride/compiler.go @@ -11,28 +11,27 @@ import ( ) func Compile(tree *Tree) (RideScript, error) { - panic("Compile") - //fCheck, err := selectFunctionChecker(tree.LibVersion) - //if err != nil { - // return nil, errors.Wrap(err, "compile") - //} - //cCheck, err := selectConstantsChecker(tree.LibVersion) - //if err != nil { - // return nil, errors.Wrap(err, "compile") - //} - //c := &compiler{ - // constants: newRideConstants(), - // checkFunction: fCheck, - // checkConstant: cCheck, - // values: make([]rideValue, 0), - // functions: make([]*localFunction, 0), - // declarations: make([]rideDeclaration, 0), - // patcher: newPatcher(), - //} - //if tree.IsDApp() { - // return c.compileDAppScript(tree) - //} - //return c.compileSimpleScript(tree) + fCheck, err := selectFunctionChecker(tree.LibVersion) + if err != nil { + return nil, errors.Wrap(err, "compile") + } + cCheck, err := selectConstantsChecker(tree.LibVersion) + if err != nil { + return nil, errors.Wrap(err, "compile") + } + c := &compiler{ + constants: newRideConstants(), + checkFunction: fCheck, + checkConstant: cCheck, + values: make([]rideValue, 0), + functions: make([]*localFunction, 0), + declarations: make([]rideDeclaration, 0), + patcher: newPatcher(), + } + if tree.IsDApp() { + return c.compileDAppScript(tree) + } + return c.compileSimpleScript(tree) } type compiler struct { diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 89044a72e3..345d7c5d22 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -581,7 +581,7 @@ func Test888(t *testing.T) { script.ByteCode) /**/ - rs, err := script.Verify(env) + rs, _ := script.Verify(env) require.Equal(t, rs.Result(), false) //require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"") } @@ -1398,7 +1398,7 @@ func TestFuncInCondState(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) - rs1, err := CallTreeVerifier(env, tree) + rs1, _ := CallTreeVerifier(env, tree) for i, c := range rs1.Calls() { t.Log(i, " ", c) } diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index e215392dde..133577dc33 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -114,7 +114,6 @@ func (a AssigmentState) Write(_ params, b []byte) { a.b.writeByte(OpCache) a.b.write(encode(a.n)) a.b.ret() - return } func (a AssigmentState) Clean() { diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index dd251dd8ee..4b6f28aa4c 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -9,7 +9,7 @@ type CallSystemState struct { name string argc uint16 // positions of arguments - argn []uint16 + //argn []uint16 // Position where we started write code for current state. startedAt uint16 //retAssig uint16 diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 3bf1a0628d..18a5903d4f 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -6,17 +6,12 @@ import "fmt" type CallUserState struct { prev Fsm params - name string - argc uint16 - // positions of arguments - //argn []uniqueid - //ret func(s CallUserState, at uint16, to uint16) + name string + argc uint16 startedAt uint16 deferred []Deferred deferreds Deferreds - - rnode []RNode } func (a CallUserState) backward(state Fsm) Fsm { diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 7184667400..4bfcfbadd3 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -26,10 +26,7 @@ type ConditionalState struct { patchFalsePosition uint16 // Offset where `if` code block ends. patchNextPosition uint16 - retAssig uint16 startedAt uint16 - trueStartedAt uint16 - falseStartedAt uint16 rets []uint16 // Clean assigments after exit. diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 080d711129..ca9421acdc 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -13,7 +13,7 @@ type Entrypoint struct { } func (a Entrypoint) Serialize(s Serializer) error { - err := s.String(rideString(a.name)) + err := s.String(a.name) if err != nil { return err } @@ -96,16 +96,7 @@ func (b *builder) ref(uint162 uint16) { func (b *builder) patch(at uint16, val []byte) { bts := b.w.Bytes()[at:] - for i := range val { - bts[i] = val[i] - } -} - -func patchBuffer(b *bytes.Buffer, at uint16, val []byte) { - bts := b.Bytes()[at:] - for i := range val { - bts[i] = val[i] - } + copy(bts, val) } func (b *builder) len() uint16 { @@ -337,36 +328,11 @@ func (a *predef) getn(id int) rideFunction { return a.prev.getn(id) } -func reverse(f []Deferred) []Deferred { - out := make([]Deferred, 0, len(f)) - for i := len(f) - 1; i >= 0; i-- { - out = append(out, f[i]) - } - return out -} - type Deferred interface { Write Clean } -//type deferred struct { -// write func() -// clean func() -//} - -//func (a deferred) Write(_ params, _ []byte) { -// if a.write != nil { -// a.write() -// } -//} -// -//func (a deferred) Clean() { -// if a.clean != nil { -// a.clean() -// } -//} - type constantDeferred struct { n uniqueid } @@ -379,36 +345,10 @@ func (a constantDeferred) Write(p params, _ []byte) { func (a constantDeferred) Clean() { } -//func NewDeferred(writeFunc func(), cleanFunc func()) Deferred { -// return deferred{ -// write: writeFunc, -// clean: cleanFunc, -// } -//} - func NewConstantDeferred(n uniqueid) constantDeferred { return constantDeferred{n: n} } -//func writeDeferred(params params, d []Deferred) { -// panic("writeDeferred 1") -// if len(d) != 1 { -// panic("writeDeferred len != 1") -// } -// d2 := reverse(d) -// -// d2[0].Write(params) -// -// for _, v := range d2 { -// v.Clean() -// } -// -// params.b.ret() -// for _, v := range d2[1:] { -// v.Write(params) -// } -//} - 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 10127cd155..24a9357c2a 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -3,7 +3,6 @@ package ride // Initial state, contains only assigments and last expression. type MainState struct { params - retAssig uint16 body []Deferred deferreds *deferreds diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index 1e86cec039..f81974ceca 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -40,10 +40,6 @@ func (a *uniqid) next() uint16 { return a.id } -func (a uniqid) cur() uint16 { - return a.id -} - type FunctionChecker func(string) (uint16, bool) type params struct { @@ -59,8 +55,6 @@ type params struct { c *cell // Transaction ID, for debug purpose. txID string - // - rnode []RNode } func (a *params) addPredefined(name string, id uniqueid, fn uint16) { diff --git a/pkg/ride/deserializer.go b/pkg/ride/deserializer.go index ee7ae9b298..be325742b5 100644 --- a/pkg/ride/deserializer.go +++ b/pkg/ride/deserializer.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "github.com/pkg/errors" + "github.com/wavesplatform/gowaves/pkg/proto" ) type Deserializer struct { @@ -59,6 +60,10 @@ func (a *Deserializer) Bytes() ([]byte, error) { if err != nil { return nil, err } + // This hack is required for correct type assertion. + if ln == 0 { + return []byte(nil), nil + } return a.readn(int(ln)) } @@ -123,6 +128,53 @@ func (a *Deserializer) RideValue() (rideType, error) { case sbytes: v, err := a.Bytes() return rideBytes(v), err + case sAddress: + v, err := a.Bytes() + if err != nil { + return nil, err + } + addr, err := proto.NewAddressFromBytes(v) + if err != nil { + return nil, err + } + return rideAddress(addr), err + case sNamedType: + v, err := a.String() + return rideNamedType{name: v}, err + case sUnit: + return newUnit(nil), nil + case sList: + size, err := a.Uint16() + if err != nil { + return nil, err + } + lst := make(rideList, size) + for i := uint16(0); i < size; i++ { + v, err := a.RideValue() + if err != nil { + return nil, err + } + lst[i] = v + } + return lst, nil + case sObject: + size, err := a.Map() + if err != nil { + return nil, err + } + obj := make(rideObject, size) + for i := uint16(0); i < size; i++ { + key, err := a.String() + if err != nil { + return nil, err + } + value, err := a.RideValue() + if err != nil { + return nil, err + } + obj[key] = value + } + return obj, nil default: if b <= 100 { return rideInt(b), nil diff --git a/pkg/ride/deserializer_test.go b/pkg/ride/deserializer_test.go index e2456780c7..420a58ce1f 100644 --- a/pkg/ride/deserializer_test.go +++ b/pkg/ride/deserializer_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/wavesplatform/gowaves/pkg/proto" ) func TestSerialization(t *testing.T) { @@ -17,7 +18,7 @@ func TestSerialization(t *testing.T) { }) t.Run("string", func(t *testing.T) { s := NewSerializer() - s.RideString("some string") + _ = s.RideString("some string") d := NewDeserializer(s.Source()) rs, _ := d.RideString() @@ -53,4 +54,77 @@ func TestSerialization(t *testing.T) { require.NoError(t, err) require.Equal(t, e, e2) }) + t.Run("address", func(t *testing.T) { + addr := rideAddress(proto.MustAddressFromString("3PKRnKhEmJbhGLDszhLmK8tptzBNjbw6wi4")) + s := NewSerializer() + require.NoError(t, addr.Serialize(s)) + + d := NewDeserializer(s.Source()) + v, err := d.RideValue() + require.NoError(t, err) + require.Equal(t, addr, v) + }) + t.Run("NamedType", func(t *testing.T) { + namedType := newDown(nil) + s := NewSerializer() + require.NoError(t, namedType.Serialize(s)) + + d := NewDeserializer(s.Source()) + v, err := d.RideValue() + require.NoError(t, err) + require.Equal(t, namedType, v) + }) + t.Run("Unit", func(t *testing.T) { + v1 := newUnit(nil) + s := NewSerializer() + require.NoError(t, v1.Serialize(s)) + + d := NewDeserializer(s.Source()) + v2, err := d.RideValue() + require.NoError(t, err) + require.Equal(t, v1, v2) + }) + t.Run("List", func(t *testing.T) { + v1 := rideList{rideInt(1), rideInt(2)} + s := NewSerializer() + require.NoError(t, v1.Serialize(s)) + + d := NewDeserializer(s.Source()) + v2, err := d.RideValue() + require.NoError(t, err) + require.Equal(t, v1, v2) + }) + t.Run("Object", func(t *testing.T) { + v1 := rideObject{"key": rideString("value")} + s := NewSerializer() + require.NoError(t, v1.Serialize(s)) + + d := NewDeserializer(s.Source()) + v2, err := d.RideValue() + require.NoError(t, err) + require.Equal(t, v1, v2) + }) + t.Run("bytes", func(t *testing.T) { + v1 := rideBytes(nil) + s := NewSerializer() + require.NoError(t, v1.Serialize(s)) + + d := NewDeserializer(s.Source()) + v2, err := d.RideValue() + require.NoError(t, err) + require.Equal(t, v1, v2) + }) +} + +func TestSerdeTransaction(t *testing.T) { + obj := testExchangeWithProofsToObject() + + s := NewSerializer() + require.NoError(t, obj.Serialize(s)) + + d := NewDeserializer(s.Source()) + v, err := d.RideValue() + require.NoError(t, err) + + require.Equal(t, obj, v) } diff --git a/pkg/ride/evaluation_result.go b/pkg/ride/evaluation_result.go new file mode 100644 index 0000000000..184fb47aaf --- /dev/null +++ b/pkg/ride/evaluation_result.go @@ -0,0 +1,28 @@ +package ride + +type EvaluationResult struct { +} + +func (a EvaluationResult) IsInterrupted() bool { + panic("unimplemented!") +} + +func (a EvaluationResult) Interrupted() *Executable { + panic("unimplemented!") +} + +func (a EvaluationResult) IsResult() bool { + panic("unimplemented!") +} + +func (a EvaluationResult) Result() ScriptResult { + panic("unimplemented!") +} + +func (a EvaluationResult) IsError() bool { + panic("unimplemented!") +} + +func (a EvaluationResult) Error() error { + panic("unimplemented!") +} diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 190808c2bb..3c07c721b5 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -9,6 +9,8 @@ type Executable struct { LibVersion int IsDapp bool hasVerifier bool + position int // Non-default value assumes interrupted evaluation. + stack []rideType ByteCode []byte EntryPoints map[string]Entrypoint References map[uniqueid]point @@ -18,7 +20,18 @@ func (a *Executable) HasVerifier() bool { return a.hasVerifier } +func (a *Executable) Interrupted() bool { + return a.position != 0 +} + +func (a *Executable) Continue() (RideResult, error) { + panic("unimplemented!") +} + func (a *Executable) Verify(environment RideEnvironment) (RideResult, error) { + if a.Interrupted() { + return nil, errors.New("illegal `Verify` call on interrupted state") + } if a.IsDapp { if !a.HasVerifier() { return nil, errors.Errorf("no verifier attached to script") @@ -32,6 +45,9 @@ func (a *Executable) Verify(environment RideEnvironment) (RideResult, error) { } func (a *Executable) Entrypoint(name string) (Entrypoint, error) { + if a.Interrupted() { + return Entrypoint{}, errors.New("illegal `Entrypoint` call on interrupted state") + } v, ok := a.EntryPoints[name] if !ok { return Entrypoint{}, errors.Errorf("entrypoint %s not found", name) @@ -82,6 +98,9 @@ func (a *Executable) runWithoutChecks(environment RideEnvironment, name string, } func (a *Executable) Invoke(env RideEnvironment, name string, arguments []rideType) (RideResult, error) { + if a.Interrupted() { + return nil, errors.New("illegal `Invoke` call on interrupted state") + } if name == "" { return nil, errors.Errorf("expected func name, found \"\"") } diff --git a/pkg/ride/program.go b/pkg/ride/program.go index a701d41c45..0db856366a 100644 --- a/pkg/ride/program.go +++ b/pkg/ride/program.go @@ -17,6 +17,10 @@ type SimpleScript struct { Constants []rideType } +func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { + panic("implement me") +} + /* func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { fs, err := selectFunctions(s.LibVersion) diff --git a/pkg/ride/reverse_tree.go b/pkg/ride/reverse_tree.go index 46bdb1a9b2..73bfe8fec9 100644 --- a/pkg/ride/reverse_tree.go +++ b/pkg/ride/reverse_tree.go @@ -1,711 +1 @@ package ride - -import ( - "fmt" -) - -func ReverseTree(n []Node) { - for i := len(n) - 1; i >= 0; i-- { - - } -} - -/* -func reverseTree(n Node, r []*RLet) RNode { - switch v := n.(type) { - case *FunctionDeclarationNode: - return &RFunc{ - Invocation: v.invocationParameter, - Name: v.Name, - Arguments: v.Arguments, - Body: reverseTree(v.Body, r), - } - case *LongNode: - return &RLong{Value: v.Value} - case *FunctionCallNode: - args := make([]RNode, len(v.Arguments)) - for i := range v.Arguments { - args[i] = reverseTree(v.Arguments[i], nil) - } - return &RCall{Name: v.Name, Arguments: args, Assigments: r} - case *ReferenceNode: - return &RRef{Name: v.Name, Assigments: r} - case *AssignmentNode: - return reverseTree(v.Block, append(r, &RLet{Name: v.Name, Body: reverseTree(v.Expression, r)})) - case *ConditionalNode: - return &RCond{ - Cond: reverseTree(v.Condition, nil), - True: reverseTree(v.TrueExpression, nil), - False: reverseTree(v.FalseExpression, nil), - Assigments: r, - } - case *StringNode: - return &RString{Value: v.Value} - default: - panic(fmt.Sprintf("unknown type %T", n)) - } -} -*/ - -// -//func walkAssigments(n Node, r []*RLet) ([]*RLet, Node) { -// switch v := n.(type) { -// case *AssignmentNode: -// r = append(r, &RLet{ -// Name: v.Name, -// N: 0, -// Body: reverseTree(v.Expression), -// }) -// return walkAssigments(v.Block, r) -// default: -// return r, v -// } -//} - -//func compileReverse(r RNode, out *bytes.Buffer) { -// switch t := r.(type) { -// case *RCall: -// for i, v := range reverseCallTree(t.CallTree()) { -// -// } -// -// out.Write() -// } -// -//} - -type startpoint struct { - fns []func() - default_ func() -} - -func (a *startpoint) push(f func()) { - a.fns = append(a.fns, f) -} - -func (a *startpoint) evalAndPop() { - if len(a.fns) > 0 { - a.fns[len(a.fns)-1]() - a.fns = a.fns[:len(a.fns)-1] - } else { - a.default_() - } - -} - -//func compileReversedTree(nodes []RNode, libVersion int, isDapp bool, hasVerifier bool) (*Executable, error) { -// var condPos []uint16 -// refs := newReferences(nil) -// out := bytes.Buffer{} -// out.WriteByte(OpReturn) -// out.WriteByte(OpReturn) -// c := newCell() -// u := uniqid{} -// u.next() -// entrypoints := make(map[string]Entrypoint) -// -// st := startpoint{ -// default_: func() { -// entrypoints[""] = Entrypoint{ -// name: "", -// at: uint16(out.Len()), -// argn: 0, -// } -// }, -// } -// st.evalAndPop() -// -// for k, v := range predefinedFunctions { -// id := uint16(math.MaxUint16 - k) -// refs.set(v.name, id) -// c.set(id, nil, id, 0, false, v.name) -// } -// -// // -// for _, v := range nodes { -// switch v := v.(type) { -// case *RDef: -// n := u.next() -// refs.set(v.Name, n) -// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) -// for range v.Arguments { -// u.next() -// } -// case *RConst: -// n := u.next() -// c.set(n, v.Value, 0, 0, true, fmt.Sprintf("constant %q", v.Value)) -// out.WriteByte(OpRef) -// out.Write(encode(n)) -// case *RCall: -// if n, ok := refs.get(v.Name); ok { -// out.WriteByte(OpRef) -// out.Write(encode(n)) -// continue -// } -// fCheck, err := selectFunctionChecker(libVersion) -// if err != nil { -// return nil, err -// } -// out.WriteByte(OpExternalCall) -// id, ok := fCheck(v.Name) -// if !ok { -// return nil, errors.Errorf("invalid func name `%s`", v.Name) -// } -// out.Write(encode(id)) -// out.Write(encode(v.Argn)) -// case *RReferenceNode: -// n, ok := refs.get(v.Name) -// if !ok { -// return nil, errors.Errorf("reference `%s` not found", v.Name) -// } -// out.WriteByte(OpRef) -// out.Write(encode(n)) -// case *RLet: -// n := u.next() -// refs.set(v.Name, n) -// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) -// n, ok := refs.get(v.Name) -// if !ok { -// return nil, errors.Errorf("reference `%s` not found", v.Name) -// } -// e, ok := c.values[n] -// if !ok { -// return nil, errors.Errorf("cell `%d` not found", n) -// } -// e.position = uint16(out.Len()) -// c.values[n] = e -// case *RFunc: -// n := u.next() -// refs.set(v.Name, n) -// refs = newReferences(refs) -// c.set(n, nil, 0, 0, false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) -// for i := range v.ArgumentsWithInvocation { -// z := u.next() -// c.set(z, nil, 0, 0, false, fmt.Sprintf("ref %d, func arg #%d %s", z, i, v.Name)) -// refs.set(v.ArgumentsWithInvocation[i], z) -// } -// if v.Invocation != "" { -// st.push(func() { -// entrypoints[v.Name] = Entrypoint{ -// name: v.Name, -// at: uint16(out.Len()), -// argn: uint16(len(v.Arguments)), -// } -// for i := len(v.Arguments) + 1; i > 0; i-- { -// out.WriteByte(OpCache) -// out.Write(encode(n + uint16(i))) -// out.WriteByte(OpPop) -// } -// }) -// } else { -// st.push(func() { -// c.set(n, nil, 0, uint16(out.Len()), false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) -// for i := len(v.ArgumentsWithInvocation); i > 0; i-- { -// out.WriteByte(OpCache) -// out.Write(encode(n + uint16(i))) -// out.WriteByte(OpPop) -// } -// }) -// } -// case *RFuncEnd: -// refs = refs.pop() -// -// case *RRet: -// out.WriteByte(OpReturn) -// case *RCond: -// condPos = append(condPos, uint16(out.Len())) -// out.WriteByte(OpJumpIfFalse) -// out.Write(make([]byte, 6)) -// case *RCondTrue: -// pos := condPos[len(condPos)-1] -// st.push(func() { -// patchBuffer(&out, pos+1, encode(uint16(out.Len()))) -// }) -// case *RCondFalse: -// pos := condPos[len(condPos)-1] -// st.push(func() { -// patchBuffer(&out, pos+3, encode(uint16(out.Len()))) -// }) -// -// case *RCondEnd: -// pos := condPos[len(condPos)-1] -// patchBuffer(&out, pos+5, encode(uint16(out.Len()))) -// condPos = condPos[:len(condPos)-1] -// case *RStart: -// st.evalAndPop() -// -// case *RProperty: -// out.WriteByte(OpProperty) -// -// default: -// panic(fmt.Sprintf("unknown type %T", v)) -// } -// -// } -// -// // Most recent code line. -// out.WriteByte(OpReturn) -// -// if isDapp && hasVerifier { -// entrypoints[""] = entrypoints["verify"] -// } -// -// e := Executable{ -// LibVersion: libVersion, -// IsDapp: isDapp, -// hasVerifier: hasVerifier, -// ByteCode: out.Bytes(), -// EntryPoints: entrypoints, -// References: c.values, -// } -// -// return &e, nil -//} - -//func compileReversedTree(nodes []RNode, libVersion int, isDapp bool, hasVerifier bool) (*Executable, error) { -// var condPos []uint16 -// refs := newReferences(nil) -// out := bytes.Buffer{} -// out.WriteByte(OpReturn) -// out.WriteByte(OpReturn) -// c := newCell() -// u := uniqid{} -// u.next() -// entrypoints := make(map[string]Entrypoint) -// -// st := startpoint{ -// default_: func() { -// entrypoints[""] = Entrypoint{ -// name: "", -// at: uint16(out.Len()), -// argn: 0, -// } -// }, -// } -// st.evalAndPop() -// -// for k, v := range predefinedFunctions { -// id := uint16(math.MaxUint16 - k) -// refs.setAssigment(v.name, id) -// c.set(id, nil, id, 0, false, v.name) -// } -// -// // -// for _, v := range nodes { -// switch v := v.(type) { -// case *RDef: -// n := u.next() -// refs.set(v.Name, n) -// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) -// for range v.Arguments { -// u.next() -// } -// //case *RBody: -// // n, ok := refs.get(v.Name, n) -// // if !ok { -// // return errors.Errorf() -// // } -// case *RConst: -// n := u.next() -// c.set(n, v.Value, 0, 0, true, fmt.Sprintf("constant %q", v.Value)) -// out.WriteByte(OpRef) -// out.Write(encode(n)) -// case *RCall: -// if n, ok := refs.get(v.Name); ok { -// out.WriteByte(OpRef) -// out.Write(encode(n)) -// continue -// } -// fCheck, err := selectFunctionChecker(libVersion) -// if err != nil { -// return nil, err -// } -// out.WriteByte(OpExternalCall) -// id, ok := fCheck(v.Name) -// if !ok { -// return nil, errors.Errorf("invalid func name `%s`", v.Name) -// } -// out.Write(encode(id)) -// out.Write(encode(v.Argn)) -// case *RReferenceNode: -// n, ok := refs.get(v.Name) -// if !ok { -// return nil, errors.Errorf("reference `%s` not found", v.Name) -// } -// out.WriteByte(OpRef) -// out.Write(encode(n)) -// case *RLet: -// n := u.next() -// refs.set(v.Name, n) -// c.set(n, nil, 0, 0, false, fmt.Sprintf("rdef %d, named %s", n, v.Name)) -// n, ok := refs.get(v.Name) -// if !ok { -// return nil, errors.Errorf("reference `%s` not found", v.Name) -// } -// e, ok := c.values[n] -// if !ok { -// return nil, errors.Errorf("cell `%d` not found", n) -// } -// e.position = uint16(out.Len()) -// c.values[n] = e -// case *RFunc: -// n := u.next() -// refs.set(v.Name, n) -// refs = newReferences(refs) -// c.set(n, nil, 0, 0, false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) -// for i := range v.ArgumentsWithInvocation { -// z := u.next() -// c.set(z, nil, 0, 0, false, fmt.Sprintf("ref %d, func arg #%d %s", z, i, v.Name)) -// refs.set(v.ArgumentsWithInvocation[i], z) -// } -// if v.Invocation != "" { -// st.push(func() { -// entrypoints[v.Name] = Entrypoint{ -// name: v.Name, -// at: uint16(out.Len()), -// argn: uint16(len(v.Arguments)), -// } -// for i := len(v.Arguments) + 1; i > 0; i-- { -// out.WriteByte(OpCache) -// out.Write(encode(n + uint16(i))) -// out.WriteByte(OpPop) -// } -// }) -// } else { -// st.push(func() { -// c.set(n, nil, 0, uint16(out.Len()), false, fmt.Sprintf("ref %d, func named %s", n, v.Name)) -// for i := len(v.ArgumentsWithInvocation); i > 0; i-- { -// out.WriteByte(OpCache) -// out.Write(encode(n + uint16(i))) -// out.WriteByte(OpPop) -// } -// }) -// } -// case *RFuncEnd: -// refs = refs.pop() -// -// case *RRet: -// out.WriteByte(OpReturn) -// case *RCond: -// condPos = append(condPos, uint16(out.Len())) -// out.WriteByte(OpJumpIfFalse) -// out.Write(make([]byte, 6)) -// case *RCondTrue: -// pos := condPos[len(condPos)-1] -// st.push(func() { -// patchBuffer(&out, pos+1, encode(uint16(out.Len()))) -// }) -// case *RCondFalse: -// pos := condPos[len(condPos)-1] -// st.push(func() { -// patchBuffer(&out, pos+3, encode(uint16(out.Len()))) -// }) -// -// case *RCondEnd: -// pos := condPos[len(condPos)-1] -// patchBuffer(&out, pos+5, encode(uint16(out.Len()))) -// condPos = condPos[:len(condPos)-1] -// case *RStart: -// st.evalAndPop() -// -// case *RProperty: -// out.WriteByte(OpProperty) -// -// default: -// panic(fmt.Sprintf("unknown type %T", v)) -// } -// -// } -// -// // Most recent code line. -// out.WriteByte(OpReturn) -// -// if isDapp && hasVerifier { -// entrypoints[""] = entrypoints["verify"] -// } -// -// e := Executable{ -// LibVersion: libVersion, -// IsDapp: isDapp, -// hasVerifier: hasVerifier, -// ByteCode: out.Bytes(), -// EntryPoints: entrypoints, -// References: c.values, -// } -// -// return &e, nil -//} - -type ddfrs struct { -} - -/* -func reverseTree2(n Node, out []RNode, deferreds *ddfrs) []RNode { - switch t := n.(type) { - case *FunctionDeclarationNode: - out = append(out, &RDef{Name: t.Name, Arguments: t.Arguments}) - temp := []RNode{&RFunc{Name: t.Name, Arguments: t.Arguments, Invocation: t.invocationParameter}} - // func body - d := &ddfrs{} - temp = append(temp, reverseTree2(t.Body, nil, d)...) - // end of function - temp = append(temp, &RFuncEnd{}) - temp = append(temp, &RRet{}) - temp = append(temp, d.deferreds...) - return reverseTree2(t.Block, out, deferreds) - case *AssignmentNode: - out = append([]RNode{&RDef{Name: t.Name}}, out...) - deferreds.add(&RLet{Name: t.Name}) - //d := &ddfrs{} - deferreds = reverseTree2(t.Expression, nil, deferreds) - deferreds = append(deferreds, &RRet{}) - return reverseTree2(t.Block, out, deferreds) - case *ConditionalNode: - cond := reverseTree2(t.Condition, nil, nil) - out = append(out, cond...) - out = append(out, &RCond{}) - out = append(out, &RCondTrue{}) - out = append(out, reverseTree2(t.TrueExpression, nil, nil)...) - out = append(out, &RRet{}) - out = append(out, &RCondFalse{}) - out = append(out, reverseTree2(t.FalseExpression, nil, nil)...) - out = append(out, &RRet{}) - out = append(out, &RCondEnd{}) - //if len(deferreds) > 0 { - // out = append(out, &RRet{}) - //} - //return append(out, deferreds...) - return out - case *LongNode: - return append(out, &RConst{Value: rideInt(t.Value)}) - case *FunctionCallNode: - out = append(out, flatCall(t)...) - if len(deferreds) > 0 { - out = append(out, &RRet{}) - } - return append(out, deferreds...) - case *BooleanNode: - return append(out, &RConst{Value: rideBoolean(t.Value)}) - case *StringNode: - return append(out, &RConst{Value: rideString(t.Value)}) - case *BytesNode: - return append(out, &RConst{Value: rideBytes(t.Value)}) - case *ReferenceNode: - return append(append(out, &RReferenceNode{Name: t.Name}), deferreds...) - default: - panic(fmt.Sprintf("unknown type %T", n)) - } -} -*/ - -// Check is definition. -func isDef(n []RNode) bool { - switch n[0].(type) { - case *RLet, *RFunc: - return true - default: - return false - } -} - -func appendInvocation(i string, args []string) []string { - if i != "" { - return append([]string{i}, args...) - } - return args -} - -func reverseTree3(n Node, out []RNode) []RNode { - switch t := n.(type) { - case *FunctionDeclarationNode: - out = append(out, &RFunc{ - Name: t.Name, - Arguments: t.Arguments, - Invocation: t.invocationParameter, - ArgumentsWithInvocation: appendInvocation(t.invocationParameter, t.Arguments), - }) - // func body - temp := reverseTree3(t.Body, nil) - if !isDef(temp) { - temp = append([]RNode{&RStart{}}, temp...) - } - out = append(out, temp...) - out = append(out, &RFuncEnd{}) - out = append(out, &RRet{}) - switch t.Block.(type) { - case *AssignmentNode, *FunctionDeclarationNode, nil: - return append(out, reverseTree3(t.Block, nil)...) - default: - out = append(out, &RStart{}) - return append(out, reverseTree3(t.Block, nil)...) - } - case *BooleanNode: - return append(out, &RConst{Value: rideBoolean(t.Value)}) - case *AssignmentNode: - out = append(out, &RLet{Name: t.Name}) - out = append(out, reverseTree3(t.Expression, nil)...) - out = append(out, &RRet{}) - switch t.Block.(type) { - case *AssignmentNode: - return append(out, reverseTree3(t.Block, nil)...) - case *FunctionDeclarationNode: - return append(out, reverseTree3(t.Block, nil)...) - default: - out = append(out, &RStart{}) - return append(out, reverseTree3(t.Block, nil)...) - } - case *LongNode: - return append(out, &RConst{Value: rideInt(t.Value)}) - case *StringNode: - return append(out, &RConst{Value: rideString(t.Value)}) - case *BytesNode: - return append(out, &RConst{Value: rideBytes(t.Value)}) - case *ReferenceNode: - return append(out, &RReferenceNode{Name: t.Name}) - case *FunctionCallNode: - out = append(out, flatCall2(t.Arguments)...) - out = append(out, &RCall{ - Name: t.Name, - Argn: uint16(len(t.Arguments)), - }) - return out - case *ConditionalNode: - out = append(out, flatCondNode(t)...) - return out - case *PropertyNode: - out = append(out, flatProperty(t)...) - return out - case nil: - return nil - default: - panic(fmt.Sprintf("unknown type %T", n)) - } -} - -//func CompileFlatTree(tree *Tree) (*Executable, error) { -// if tree.IsDApp() { -// var rev []RNode -// for _, v := range tree.Declarations { -// rev = append(rev, reverseTree3(v, nil)...) -// } -// for _, v := range tree.Functions { -// rev = append(rev, reverseTree3(v, nil)...) -// } -// if tree.HasVerifier() { -// rev = append(rev, reverseTree3(tree.Verifier, nil)...) -// } -// return compileReversedTree(rev, tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) -// } -// return compileReversedTree(reverseTree3(tree.Verifier, nil), tree.LibVersion, tree.IsDApp(), tree.HasVerifier()) -//} - -func flatCondNode(t *ConditionalNode) []RNode { - var out []RNode - cond := reverseTree3(t.Condition, nil) - out = append(out, cond...) - out = append(out, &RCond{}) - out = append(out, &RCondTrue{}) - switch t.TrueExpression.(type) { - case *AssignmentNode: - out = append(out, reverseTree3(t.TrueExpression, nil)...) - default: - out = append(out, &RStart{}) - out = append(out, reverseTree3(t.TrueExpression, nil)...) - } - out = append(out, &RRet{}) - out = append(out, &RCondFalse{}) - switch t.FalseExpression.(type) { - case *AssignmentNode: - out = append(out, reverseTree3(t.FalseExpression, nil)...) - default: - out = append(out, &RStart{}) - out = append(out, reverseTree3(t.FalseExpression, nil)...) - } - out = append(out, &RRet{}) - out = append(out, &RCondEnd{}) - return out -} - -//func flatCall(call *FunctionCallNode) []RNode { -// out := []RNode{ -// &RCall{ -// Name: call.Name, -// Argn: uint16(len(call.Arguments)), -// }, -// } -// for i := len(call.Arguments) - 1; i >= 0; i-- { -// switch t := call.Arguments[i].(type) { -// case *LongNode: -// out = append(out, &RConst{Value: rideInt(t.Value)}) -// case *BooleanNode: -// out = append(out, &RConst{Value: rideBoolean(t.Value)}) -// case *BytesNode: -// out = append(out, &RConst{Value: rideBytes(t.Value)}) -// case *StringNode: -// out = append(out, &RConst{Value: rideString(t.Value)}) -// case *FunctionCallNode: -// out = append(out, flatCall(t)...) -// case *ReferenceNode: -// out = append(out, &RReferenceNode{Name: t.Name}) -// case *PropertyNode: -// out = append(out, reverseRnodes(flatProperty(t))...) -// case *ConditionalNode: -// out = append(out, reverseRnodes(flatCondNode(t))...) -// default: -// panic(fmt.Sprintf("unknown type %T", call.Arguments[i])) -// } -// } -// return out -//} - -func flatCall2(Arguments []Node) []RNode { - var out = []RNode{} - for i := len(Arguments) - 1; i >= 0; i-- { - switch t := Arguments[i].(type) { - case *LongNode: - out = append([]RNode{&RConst{Value: rideInt(t.Value)}}, out...) - case *BooleanNode: - out = append([]RNode{&RConst{Value: rideBoolean(t.Value)}}, out...) - case *BytesNode: - out = append([]RNode{&RConst{Value: rideBytes(t.Value)}}, out...) - case *StringNode: - out = append([]RNode{&RConst{Value: rideString(t.Value)}}, out...) - case *FunctionCallNode: - call := flatCall2(t.Arguments) - call = append(call, &RCall{ - Name: t.Name, - Argn: t.ArgumentsCount(), - }) - out = append(call, out...) - case *ReferenceNode: - out = append([]RNode{&RReferenceNode{Name: t.Name}}, out...) - case *PropertyNode: - tmp := flatProperty(t) - out = append(tmp, out...) - case *ConditionalNode: - tmp := flatCondNode(t) - out = append(tmp, out...) - default: - panic(fmt.Sprintf("unknown type %T", Arguments[i])) - } - } - return out -} - -func flatProperty(p *PropertyNode) []RNode { - switch v := p.Object.(type) { - case *ReferenceNode: - return []RNode{&RReferenceNode{Name: v.Name}, &RConst{Value: rideString(p.Name)}, &RProperty{}} - case *PropertyNode: - return append(flatProperty(v), &RConst{Value: rideString(p.Name)}, &RProperty{}) - case *FunctionCallNode: - call := flatCall2(v.Arguments) - call = append(call, &RCall{ - Name: v.Name, - Argn: v.ArgumentsCount(), - }) - return append(call, &RConst{Value: rideString(p.Name)}, &RProperty{}) - default: - panic(fmt.Sprintf("unknown type %T", v)) - } -} diff --git a/pkg/ride/runtime.go b/pkg/ride/runtime.go index d1af48e947..42764a97d5 100644 --- a/pkg/ride/runtime.go +++ b/pkg/ride/runtime.go @@ -129,8 +129,21 @@ func (b rideBytes) get(prop string) (rideType, error) { type rideObject map[string]rideType -func (o rideObject) Serialize(Serializer) error { - panic("implement me") +func (o rideObject) Serialize(s Serializer) error { + if err := s.Type(sObject); err != nil { + return err + } + return s.Map(len(o), func(m Map) error { + for k, v := range o { + if err := m.String(k); err != nil { + return err + } + if err := v.Serialize(s); err != nil { + return err + } + } + return nil + }) } func (o rideObject) instanceOf() string { @@ -166,8 +179,11 @@ func (o rideObject) get(prop string) (rideType, error) { type rideAddress proto.Address -func (a rideAddress) Serialize(Serializer) error { - panic("implement me") +func (a rideAddress) Serialize(s Serializer) error { + if err := s.Type(sAddress); err != nil { + return err + } + return s.Bytes(a[:]) } func (a rideAddress) instanceOf() string { @@ -314,8 +330,8 @@ func (a rideAlias) get(prop string) (rideType, error) { type rideUnit struct{} -func (a rideUnit) Serialize(Serializer) error { - panic("rideUnit Serialize: implement me") +func (a rideUnit) Serialize(s Serializer) error { + return s.RideUnit() } func (a rideUnit) instanceOf() string { @@ -334,8 +350,11 @@ type rideNamedType struct { name string } -func (a rideNamedType) Serialize(serializer Serializer) error { - panic("rideNamedType Serialize: implement me") +func (a rideNamedType) Serialize(s Serializer) error { + if err := s.Type(sNamedType); err != nil { + return err + } + return s.String(a.name) } func (a rideNamedType) instanceOf() string { @@ -352,8 +371,16 @@ func (a rideNamedType) get(prop string) (rideType, error) { type rideList []rideType -func (a rideList) Serialize(Serializer) error { - panic("implement me") +func (a rideList) Serialize(s Serializer) error { + if err := s.RideList(uint16(len(a))); err != nil { + return err + } + for _, v := range a { + if err := v.Serialize(s); err != nil { + return err + } + } + return nil } func (a rideList) instanceOf() string { diff --git a/pkg/ride/serializer.go b/pkg/ride/serializer.go index 9af34515dd..75f768fbb8 100644 --- a/pkg/ride/serializer.go +++ b/pkg/ride/serializer.go @@ -9,15 +9,20 @@ import ( ) const ( - strue byte = 101 - sfalse = 102 - sint = 103 - suint16 = 104 - sbytes = 105 - sString = 106 - spoint = 107 - sMap = 108 - sNoValue = 109 + strue byte = 101 + sfalse byte = 102 + sint byte = 103 + suint16 byte = 104 + sbytes byte = 105 + sString byte = 106 + sPoint byte = 107 + sMap byte = 108 + sNoValue byte = 109 + sAddress byte = 110 + sNamedType byte = 111 + sUnit byte = 112 + sList byte = 113 + sObject byte = 114 ) type Serializer struct { @@ -63,7 +68,7 @@ func (a *Serializer) Bool(v bool) { } func (a *Serializer) Point(p point) { - a.b.WriteByte(spoint) + a.b.WriteByte(sPoint) a.Uint16(p.position) } @@ -76,6 +81,10 @@ func (a *Serializer) RideBytes(v rideBytes) error { return a.Bytes(v) } +func (a *Serializer) Type(t byte) error { + return a.b.WriteByte(t) +} + func (a *Serializer) Bytes(v []byte) error { if len(v) > math.MaxUint16 { return errors.New("bytes length overflow") @@ -100,10 +109,14 @@ func (a *Serializer) RideMap(size int) error { func (a *Serializer) RideString(v rideString) error { a.b.WriteByte(sString) - return a.String(v) + return a.String(string(v)) } -func (a *Serializer) String(v rideString) error { +func (a *Serializer) RideUnit() error { + return a.Type(sUnit) +} + +func (a *Serializer) String(v string) error { if len(v) > math.MaxUint16 { return errors.New("bytes length overflow") } @@ -125,7 +138,16 @@ func (a *Serializer) Map(size int, f func(Map) error) error { return f(a) } +func (a *Serializer) RideList(length uint16) error { + if err := a.Type(sList); err != nil { + return err + } + a.Uint16(length) + return nil +} + type Map interface { + String(string) error Uint16(v uint16) RideInt(v rideInt) error RideBytes(v rideBytes) error diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 9164f18fd2..eda3be3891 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -3,6 +3,7 @@ package ride import ( "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" + "go.uber.org/zap" ) func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { @@ -25,34 +26,34 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) if err != nil { return nil, err } - //r2, err := CallTreeVerifier(env, tree) - //if err != nil { - // return nil, err - //} + r2, err := CallTreeVerifier(env, tree) + if err != nil { + return nil, err + } + + if !r.Eq(r2) { + c1 := r.Calls() + c2 := r2.Calls() + max := len(c1) + if len(c2) > len(c1) { + max = len(c2) + } + for i := 0; i < max; i++ { + //zap.S().Error("R1 != R2: failed to call account script on transaction ") + if i <= len(c1)-1 { + zap.S().Error(i, txID, " ", c1[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + if i <= len(c2)-1 { + zap.S().Error(i, txID, " ", c2[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + } - //if !r.Eq(r2) { - // c1 := r.Calls() - // c2 := r2.Calls() - // max := len(c1) - // if len(c2) > len(c1) { - // max = len(c2) - // } - // for i := 0; i < max; i++ { - // //zap.S().Error("R1 != R2: failed to call account script on transaction ") - // if i <= len(c1)-1 { - // zap.S().Error(i, txID, " ", c1[i]) - // } else { - // zap.S().Error(i, txID, " ", "") - // } - // if i <= len(c2)-1 { - // zap.S().Error(i, txID, " ", c2[i]) - // } else { - // zap.S().Error(i, txID, " ", "") - // } - // } - // - // return nil, errors.New("R1 != R2: failed to call account script on transaction ") - //} + return nil, errors.New("R1 != R2: failed to call account script on transaction ") + } return r, nil } @@ -69,35 +70,35 @@ func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, } func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - //rs1, err := CallTreeFunction(txID, env, tree, name, args) - //if err != nil { - // return nil, errors.Wrap(err, "call function by tree") - //} + rs1, err := CallTreeFunction(txID, env, tree, name, args) + if err != nil { + return nil, errors.Wrap(err, "call function by tree") + } rs2, err := CallVmFunction(txID, env, exe, name, args) if err != nil { return rs2, errors.Wrap(err, "call function by vm") } - //if !rs1.Eq(rs2) { - // c1 := rs1.Calls() - // c2 := rs2.Calls() - // max := len(c1) - // if len(c2) > len(c1) { - // max = len(c2) - // } - // for i := 0; i < max; i++ { - // if i <= len(c1)-1 { - // zap.S().Error(i, txID, " ", c1[i]) - // } else { - // zap.S().Error(i, txID, " ", "") - // } - // if i <= len(c2)-1 { - // zap.S().Error(i, txID, " ", c2[i]) - // } else { - // zap.S().Error(i, txID, " ", "") - // } - // } - // return nil, errors.New("R1 != R2: failed to call account script on transaction ") - //} + if !rs1.Eq(rs2) { + c1 := rs1.Calls() + c2 := rs2.Calls() + max := len(c1) + if len(c2) > len(c1) { + max = len(c2) + } + for i := 0; i < max; i++ { + if i <= len(c1)-1 { + zap.S().Error(i, txID, " ", c1[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + if i <= len(c2)-1 { + zap.S().Error(i, txID, " ", c2[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + } + return nil, errors.New("R1 != R2: failed to call account script on transaction ") + } return rs2, nil } diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index a0a559db1a..1ba4397c42 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -383,10 +383,11 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { } args[i] = esValue{id: an, value: av} } - e.s.cs = append(e.s.cs, make([]esValue, len(args))) - for i, arg := range args { - e.s.cs[len(e.s.cs)-1][i] = arg - } + //e.s.cs = append(e.s.cs, make([]esValue, len(args))) + e.s.cs = append(e.s.cs, args) + //for i, arg := range args { + // e.s.cs[len(e.s.cs)-1][i] = arg + //} var tmp int tmp, e.s.cl = e.s.cl, cl r, err := e.walk(uf.Body) diff --git a/pkg/state/common_test.go b/pkg/state/common_test.go index c23877b066..99c0b4d6d5 100644 --- a/pkg/state/common_test.go +++ b/pkg/state/common_test.go @@ -377,7 +377,7 @@ func (s *testStorageObjects) createAsset(t *testing.T, assetID crypto.Digest) *a func (s *testStorageObjects) createSmartAsset(t *testing.T, assetID crypto.Digest) { s.addBlock(t, blockID0) - err := s.entities.scriptsStorage.setAssetScript(assetID, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0) + err := s.entities.scriptsStorage.setAssetScript(assetID, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0, "") assert.NoError(t, err, "setAssetScript failed") s.flush(t) } diff --git a/pkg/state/fee_validation_test.go b/pkg/state/fee_validation_test.go index f8d0c1dc7e..23c537b35c 100644 --- a/pkg/state/fee_validation_test.go +++ b/pkg/state/fee_validation_test.go @@ -25,7 +25,7 @@ func TestAssetScriptExtraFee(t *testing.T) { // Set script. to.stor.addBlock(t, blockID0) addr := testGlobal.senderInfo.addr - err = to.stor.entities.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0) + err = to.stor.entities.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0, "") assert.NoError(t, err) // Burn. @@ -63,7 +63,7 @@ func TestAccountScriptExtraFee(t *testing.T) { // Set script. to.stor.addBlock(t, blockID0) addr := testGlobal.senderInfo.addr - err = to.stor.entities.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0) + err = to.stor.entities.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0, "") assert.NoError(t, err) // Burn. diff --git a/pkg/state/invoke_applier.go b/pkg/state/invoke_applier.go index 9f369815af..3dff1a430b 100644 --- a/pkg/state/invoke_applier.go +++ b/pkg/state/invoke_applier.go @@ -522,15 +522,14 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf if err != nil { return nil, errors.Wrap(err, "recipientToAddress() failed") } - //tree, err := ia.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !info.initialisation) exe, err := ia.stor.scriptsStorage.newestBytecodeByAddr(*scriptAddr, !info.initialisation) if err != nil { return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) } - //tree, err := ia.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !info.initialisation) - //if err != nil { - // return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) - //} + tree, err := ia.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !info.initialisation) + if err != nil { + return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) + } scriptPK, err := ia.stor.scriptsStorage.newestScriptPKByAddr(*scriptAddr, !info.initialisation) if err != nil { return nil, errors.Wrapf(err, "failed to get script's public key on address '%s'", scriptAddr.String()) @@ -559,7 +558,7 @@ func (ia *invokeApplier) applyInvokeScript(tx *proto.InvokeScriptWithProofs, inf return nil, err } // Call script function. - ok, scriptActions, err := ia.sc.invokeFunction(exe, tx, info.blockInfo, *scriptAddr, info.initialisation, nil) + ok, scriptActions, err := ia.sc.invokeFunction(exe, tx, info.blockInfo, *scriptAddr, info.initialisation, tree) if !ok { // When ok is false, it means that we could not even start invocation. // We just return error in such case. diff --git a/pkg/state/invoke_applier_test.go b/pkg/state/invoke_applier_test.go index 2ac7124666..5ee9ce7763 100644 --- a/pkg/state/invoke_applier_test.go +++ b/pkg/state/invoke_applier_test.go @@ -75,7 +75,7 @@ func (to *invokeApplierTestObjects) setScript(t *testing.T, addr proto.Address, require.NoError(t, err) err = to.state.stor.scriptsComplexity.saveComplexitiesForAddr(addr, map[int]ride.TreeEstimation{1: estimation}, blockID0) assert.NoError(t, err, "failed to save complexity for address") - err = to.state.stor.scriptsStorage.setAccountScript(addr, script, pk, blockID0) + err = to.state.stor.scriptsStorage.setAccountScript(addr, script, pk, blockID0, "") assert.NoError(t, err, "failed to set account script") } diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index c4c49de2f7..a1f2ee0ae1 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -42,10 +42,10 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return err } - //tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) - //if err != nil { - // return errors.Wrap(err, "failed to retrieve account script") - //} + tree, err := a.stor.scriptsStorage.newestScriptByAddr(sender, !initialisation) + if err != nil { + return errors.Wrap(err, "failed to retrieve account script") + } exe, err := a.stor.scriptsStorage.newestBytecodeByAddr(sender, !initialisation) if err != nil { return errors.Wrap(err, "failed to retrieve account script") @@ -61,7 +61,7 @@ func (a *scriptCaller) callAccountScriptWithOrder(order proto.Order, lastBlockIn if err != nil { return errors.Wrap(err, "failed to convert order") } - r, err := ride.CallVerifier("scriptCaller callAccountScriptWithOrder", env, nil, exe) + r, err := ride.CallVerifier("scriptCaller callAccountScriptWithOrder", env, tree, exe) if err != nil { return errors.Wrapf(err, "failed to call account script on order '%s'", base58.Encode(id)) } @@ -94,10 +94,10 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn if err != nil { return err } - //tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) - //if err != nil { - // return err - //} + tree, err := a.stor.scriptsStorage.newestScriptByAddr(senderAddr, !initialisation) + if err != nil { + return err + } exe, err := a.stor.scriptsStorage.newestBytecodeByAddr(senderAddr, !initialisation) if err != nil { return err @@ -114,7 +114,7 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } //zap.S().Debug(tx.GetID(a.settings.AddressSchemeCharacter)) - r, err := ride.CallVerifier(txID, env, nil, exe) + r, err := ride.CallVerifier(txID, env, tree, exe) if err != nil { return errors.Wrapf(err, "failed to call account script on transaction '%s'", base58.Encode(id)) } @@ -147,10 +147,10 @@ func (a *scriptCaller) callAccountScriptWithTx(tx proto.Transaction, lastBlockIn } func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID crypto.Digest, lastBlockInfo *proto.BlockInfo, initialisation bool, acceptFailed bool) (ride.RideResult, error) { - //tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !initialisation) - //if err != nil { - // return nil, err - //} + tree, err := a.stor.scriptsStorage.newestScriptByAsset(assetID, !initialisation) + if err != nil { + return nil, err + } exe, err := a.stor.scriptsStorage.newestBytecodeByAsset(assetID, !initialisation) if err != nil { return nil, err @@ -171,7 +171,7 @@ func (a *scriptCaller) callAssetScriptCommon(env *ride.Environment, assetID cryp env.SetThisFromAssetInfo(assetInfo) } env.SetLastBlock(lastBlockInfo) - r, err := ride.CallVerifier("scriptCaller callAssetScriptCommon", env, nil, exe) + r, err := ride.CallVerifier("scriptCaller callAssetScriptCommon", env, tree, exe) if err != nil { return nil, errors.Wrapf(err, "failed to call script on asset '%s'", assetID.String()) } @@ -246,9 +246,7 @@ func (a *scriptCaller) invokeFunction(exe *ride.Executable, tx *proto.InvokeScri // zap.S().Errorf("%d argument %+v, %T", i, v, v) //} - r, err := ride.CallFunction(txID, env, exe, nil, tx.FunctionCall.Name, tx.FunctionCall.Arguments) - //r, err := ride.CallVmFunction(txID, env, exe, tx.FunctionCall.Name, tx.FunctionCall.Arguments) - //r, err := ride.CallTreeFunction(txID, env, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) + r, err := ride.CallFunction(txID, env, exe, tree, tx.FunctionCall.Name, tx.FunctionCall.Arguments) if err != nil { return false, nil, errors.Wrapf(err, "invocation of transaction '%s' failed", tx.ID.String()) } diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 3a62b350c7..b6e71e7400 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -9,7 +9,6 @@ import ( "github.com/wavesplatform/gowaves/pkg/libs/deserializer" "github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/ride" - "go.uber.org/zap" ) const ( @@ -20,33 +19,12 @@ const ( ) func scriptBytesToTree(script proto.Script) (*ride.Tree, error) { - if len(script) == 0 { panic("scriptBytesToTree") } - zap.S().Debug("scriptBytesToTree scrip %v, len %d", script, len(script)) - return ride.Parse(script) } -func scriptBytesToVmBytes(script proto.Script) ([]byte, error) { - panic("unreachable") - p, err := scriptBytesToTree(script) - if err != nil { - return nil, err - } - exe, err := ride.CompileTree("performSetScriptWithProofs", p) - if err != nil { - return nil, err - } - s := ride.NewSerializer() - err = exe.Serialize(s) - if err != nil { - return nil, err - } - return s.Source(), nil -} - func scriptBytesToExecutable(script proto.Script) (*ride.Executable, error) { return ride.DeserializeExecutable(script) } @@ -478,7 +456,9 @@ func (ss *scriptsStorage) accountHasScript(addr proto.Address, filter bool) (boo } func (ss *scriptsStorage) newestScriptByAddr(addr proto.Address, filter bool) (*ride.Tree, error) { - panic("unreacheable!") + if true { + panic("unreacheable!") + } key := accountScriptKey{addr} keyBytes := key.bytes() tree, err := ss.newestScriptAstByKey(keyBytes, filter) diff --git a/pkg/state/scripts_storage_test.go b/pkg/state/scripts_storage_test.go index 372f51c8e8..e8e67f7e4f 100644 --- a/pkg/state/scripts_storage_test.go +++ b/pkg/state/scripts_storage_test.go @@ -39,7 +39,7 @@ func TestSetAccountScript(t *testing.T) { to.stor.addBlock(t, blockID0) addr := testGlobal.senderInfo.addr - err = to.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0) + err = to.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0, "") assert.NoError(t, err, "setAccountScript() failed") // Test newest before flushing. @@ -88,7 +88,7 @@ func TestSetAccountScript(t *testing.T) { assert.Equal(t, testGlobal.scriptAst, scriptAst2) // Test discarding script. - err = to.scriptsStorage.setAccountScript(addr, proto.Script{}, testGlobal.senderInfo.pk, blockID0) + err = to.scriptsStorage.setAccountScript(addr, proto.Script{}, testGlobal.senderInfo.pk, blockID0, "") assert.NoError(t, err, "setAccountScript() failed") // Test newest before flushing. @@ -148,7 +148,7 @@ func TestSetAssetScript(t *testing.T) { to.stor.addBlock(t, blockID0) assetID := testGlobal.asset0.asset.ID - err = to.scriptsStorage.setAssetScript(assetID, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0) + err = to.scriptsStorage.setAssetScript(assetID, testGlobal.scriptBytes, testGlobal.senderInfo.pk, blockID0, "") assert.NoError(t, err, "setAssetScript() failed") // Test newest before flushing. @@ -183,7 +183,7 @@ func TestSetAssetScript(t *testing.T) { assert.Equal(t, testGlobal.scriptAst, scriptAst2) // Test discarding script. - err = to.scriptsStorage.setAssetScript(assetID, proto.Script{}, testGlobal.senderInfo.pk, blockID0) + err = to.scriptsStorage.setAssetScript(assetID, proto.Script{}, testGlobal.senderInfo.pk, blockID0, "") assert.NoError(t, err, "setAssetScript() failed") // Test newest before flushing. diff --git a/pkg/state/transaction_checker_test.go b/pkg/state/transaction_checker_test.go index 52f3aec90e..64e7518fd0 100644 --- a/pkg/state/transaction_checker_test.go +++ b/pkg/state/transaction_checker_test.go @@ -458,7 +458,7 @@ func TestCheckExchangeWithSig(t *testing.T) { // Set script. to.stor.addBlock(t, blockID0) addr := testGlobal.recipientInfo.addr - err = to.stor.entities.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.recipientInfo.pk, blockID0) + err = to.stor.entities.scriptsStorage.setAccountScript(addr, testGlobal.scriptBytes, testGlobal.recipientInfo.pk, blockID0, "") assert.NoError(t, err) _, err = to.tc.checkExchangeWithSig(tx, info) @@ -1052,7 +1052,7 @@ func TestCheckSetAssetScriptWithProofs(t *testing.T) { assert.Error(t, err, "checkSetAssetScriptWithProofs did not fail with non-smart asset") // Make it smart. - err = to.stor.entities.scriptsStorage.setAssetScript(tx.AssetID, tx.Script, tx.SenderPK, blockID0) + err = to.stor.entities.scriptsStorage.setAssetScript(tx.AssetID, tx.Script, tx.SenderPK, blockID0, "") assert.NoError(t, err, "setAssetScript failed") // Now should pass. diff --git a/pkg/state/transaction_performer_test.go b/pkg/state/transaction_performer_test.go index 3966be521e..39be2dc32c 100644 --- a/pkg/state/transaction_performer_test.go +++ b/pkg/state/transaction_performer_test.go @@ -608,7 +608,7 @@ func TestPerformSetAssetScriptWithProofs(t *testing.T) { assert.Equal(t, testGlobal.scriptAst, scriptAst) // Test discarding script. - err = to.stor.entities.scriptsStorage.setAssetScript(assetID, proto.Script{}, crypto.PublicKey{}, blockID0) + err = to.stor.entities.scriptsStorage.setAssetScript(assetID, proto.Script{}, crypto.PublicKey{}, blockID0, "") assert.NoError(t, err, "setAssetScript() failed") // Test newest before flushing. From 3e16ec5cea3b42788073663059c63417b88cf48a Mon Sep 17 00:00:00 2001 From: Frozen Date: Tue, 9 Feb 2021 19:49:08 +0300 Subject: [PATCH 37/55] Fix panic. --- pkg/ride/tree_estimatorV3.go | 2 +- pkg/state/scripts_storage.go | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/ride/tree_estimatorV3.go b/pkg/ride/tree_estimatorV3.go index de4a443e79..7c88c611d9 100644 --- a/pkg/ride/tree_estimatorV3.go +++ b/pkg/ride/tree_estimatorV3.go @@ -67,7 +67,7 @@ func (s *estimationScopeV3) setFunction(id string, cost int, usages []string) { s.functions.set(id, cost, usages) } -func (s *estimationScopeV3) function(id string) (int, []string, error) { +func (s *estimationScopeV3) function(id string) (cost int, usages []string, err error) { if c, ok := s.builtin[id]; ok { return c, nil, nil } diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index b6e71e7400..982ff25161 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -456,9 +456,6 @@ func (ss *scriptsStorage) accountHasScript(addr proto.Address, filter bool) (boo } func (ss *scriptsStorage) newestScriptByAddr(addr proto.Address, filter bool) (*ride.Tree, error) { - if true { - panic("unreacheable!") - } key := accountScriptKey{addr} keyBytes := key.bytes() tree, err := ss.newestScriptAstByKey(keyBytes, filter) From 73a8ce5907560fed89461f6819a801af4b79a6b0 Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 12 Feb 2021 18:07:48 +0300 Subject: [PATCH 38/55] Remove caching duplicates. --- go.mod | 2 +- go.sum | 2 + pkg/proto/scripting.go | 62 ++++++++++++++++-- pkg/proto/types.go | 37 +++++++++++ pkg/ride/compiler2_test.go | 20 +++++- pkg/ride/compiler_call_system.go | 7 +- pkg/ride/compiler_call_user.go | 109 ++++++------------------------- pkg/ride/compiler_helpers.go | 5 ++ pkg/ride/compiler_main.go | 1 + pkg/ride/compiler_state.go | 2 +- pkg/ride/result.go | 3 +- pkg/ride/tree_evaluation.go | 12 ++++ pkg/ride/vm_estimator.go | 20 ++++++ 13 files changed, 178 insertions(+), 104 deletions(-) create mode 100644 pkg/ride/vm_estimator.go diff --git a/go.mod b/go.mod index c79c72ba77..42ec4e405c 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/starius/emsort v0.0.0-20191221202443-6f2fbdee4781 github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d github.com/valyala/bytebufferpool v1.0.0 github.com/xenolf/lego v2.7.2+incompatible diff --git a/go.sum b/go.sum index 7a2d2978fa..454429caa3 100644 --- a/go.sum +++ b/go.sum @@ -261,6 +261,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= diff --git a/pkg/proto/scripting.go b/pkg/proto/scripting.go index 5488019e36..7e4ba7e3a5 100644 --- a/pkg/proto/scripting.go +++ b/pkg/proto/scripting.go @@ -1,8 +1,8 @@ package proto import ( + "bytes" "encoding/binary" - "fmt" "unicode/utf16" "github.com/pkg/errors" @@ -19,9 +19,7 @@ func (a ScriptActions) Eq(b ScriptActions) bool { } for i := range a { - left := fmt.Sprintf("%+v", a[i]) - right := fmt.Sprintf("%+v", b[i]) - if left != right { + if !a[i].Eq(b[i]) { return false } } @@ -31,6 +29,7 @@ func (a ScriptActions) Eq(b ScriptActions) bool { // ScriptAction common interface of script invocation actions. type ScriptAction interface { scriptAction() + Eq(ScriptAction) bool } // DataEntryScriptAction is an action to manipulate account data state. @@ -40,6 +39,14 @@ type DataEntryScriptAction struct { func (a DataEntryScriptAction) scriptAction() {} +func (a DataEntryScriptAction) Eq(another ScriptAction) bool { + b, ok := another.(*DataEntryScriptAction) + if !ok { + return false + } + return a.Entry.Eq(b.Entry) +} + func (a *DataEntryScriptAction) ToProtobuf() *g.DataTransactionData_DataEntry { return a.Entry.ToProtobuf() } @@ -53,6 +60,14 @@ type TransferScriptAction struct { func (a TransferScriptAction) scriptAction() {} +func (a TransferScriptAction) Eq(other ScriptAction) bool { + b, ok := other.(*TransferScriptAction) + if !ok { + return false + } + return a.Amount == b.Amount && a.Asset == b.Asset && a.Recipient.Eq(b.Recipient) +} + func (a *TransferScriptAction) ToProtobuf() (*g.InvokeScriptResult_Payment, error) { amount := &g.Amount{ AssetId: a.Asset.ToID(), @@ -79,6 +94,21 @@ type IssueScriptAction struct { func (a IssueScriptAction) scriptAction() {} +func (a IssueScriptAction) Eq(other ScriptAction) bool { + b, ok := other.(*IssueScriptAction) + if !ok { + return false + } + return a.ID == b.ID && + a.Name == b.Name && + a.Description == b.Description && + a.Quantity == b.Quantity && + a.Decimals == b.Decimals && + a.Reissuable == b.Reissuable && + bytes.Equal(a.Script, b.Script) && + a.Nonce == b.Nonce +} + func (a *IssueScriptAction) ToProtobuf() *g.InvokeScriptResult_Issue { return &g.InvokeScriptResult_Issue{ AssetId: a.ID.Bytes(), @@ -127,6 +157,14 @@ type ReissueScriptAction struct { func (a ReissueScriptAction) scriptAction() {} +func (a ReissueScriptAction) Eq(other ScriptAction) bool { + b, ok := other.(*ReissueScriptAction) + if !ok { + return false + } + return a.Reissuable == b.Reissuable && a.AssetID == b.AssetID && a.Quantity == b.Quantity +} + func (a *ReissueScriptAction) ToProtobuf() *g.InvokeScriptResult_Reissue { return &g.InvokeScriptResult_Reissue{ AssetId: a.AssetID.Bytes(), @@ -143,6 +181,14 @@ type BurnScriptAction struct { func (a BurnScriptAction) scriptAction() {} +func (a BurnScriptAction) Eq(other ScriptAction) bool { + b, ok := other.(*BurnScriptAction) + if !ok { + return false + } + return a.AssetID == b.AssetID && a.Quantity == b.Quantity +} + func (a *BurnScriptAction) ToProtobuf() *g.InvokeScriptResult_Burn { return &g.InvokeScriptResult_Burn{ AssetId: a.AssetID.Bytes(), @@ -158,6 +204,14 @@ type SponsorshipScriptAction struct { func (a SponsorshipScriptAction) scriptAction() {} +func (a SponsorshipScriptAction) Eq(other ScriptAction) bool { + b, ok := other.(*SponsorshipScriptAction) + if !ok { + return false + } + return a.AssetID == b.AssetID && a.MinFee == b.MinFee +} + func (a *SponsorshipScriptAction) ToProtobuf() *g.InvokeScriptResult_SponsorFee { return &g.InvokeScriptResult_SponsorFee{ MinFee: &g.Amount{ diff --git a/pkg/proto/types.go b/pkg/proto/types.go index 55b21209b3..ce8c41a32a 100644 --- a/pkg/proto/types.go +++ b/pkg/proto/types.go @@ -1713,6 +1713,8 @@ type DataEntry interface { BinarySize() int ToProtobuf() *g.DataTransactionData_DataEntry + + Eq(DataEntry) bool } var bytesToDataEntry = map[DataValueType]reflect.Type{ @@ -1768,6 +1770,13 @@ type IntegerDataEntry struct { Value int64 } +func (e IntegerDataEntry) Eq(other DataEntry) bool { + if b, ok := other.(*IntegerDataEntry); ok { + return e.Key == b.Key && e.Value == b.Value + } + return false +} + func (e IntegerDataEntry) ToProtobuf() *g.DataTransactionData_DataEntry { return &g.DataTransactionData_DataEntry{ Key: e.Key, @@ -1896,6 +1905,13 @@ type BooleanDataEntry struct { Value bool } +func (e BooleanDataEntry) Eq(other DataEntry) bool { + if b, ok := other.(*BooleanDataEntry); ok { + return e.Key == b.Key && e.Value == b.Value + } + return false +} + func (e BooleanDataEntry) ToProtobuf() *g.DataTransactionData_DataEntry { return &g.DataTransactionData_DataEntry{ Key: e.Key, @@ -2028,6 +2044,13 @@ type BinaryDataEntry struct { Value []byte } +func (e BinaryDataEntry) Eq(other DataEntry) bool { + if b, ok := other.(*BinaryDataEntry); ok { + return e.Key == b.Key && bytes.Equal(e.Value, b.Value) + } + return false +} + func (e BinaryDataEntry) ToProtobuf() *g.DataTransactionData_DataEntry { return &g.DataTransactionData_DataEntry{ Key: e.Key, @@ -2163,6 +2186,13 @@ type StringDataEntry struct { Value string } +func (e StringDataEntry) Eq(other DataEntry) bool { + if b, ok := other.(*StringDataEntry); ok { + return e.Key == b.Key && e.Value == b.Value + } + return false +} + func (e StringDataEntry) ToProtobuf() *g.DataTransactionData_DataEntry { return &g.DataTransactionData_DataEntry{ Key: e.Key, @@ -2297,6 +2327,13 @@ type DeleteDataEntry struct { Key string } +func (e DeleteDataEntry) Eq(other DataEntry) bool { + if b, ok := other.(*DeleteDataEntry); ok { + return e.Key == b.Key + } + return false +} + func (e DeleteDataEntry) ToProtobuf() *g.DataTransactionData_DataEntry { return &g.DataTransactionData_DataEntry{ Key: e.Key, diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 345d7c5d22..770bec3ef5 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -142,11 +142,10 @@ func TestCallExternal(t *testing.T) { OpReturn, OpReturn, OpRef, 0, 1, - OpCache, 0, 1, OpRef, 0, 1, - OpCache, 0, 1, OpExternalCall, 0, 3, 0, 2, OpReturn, + OpReturn, }, f.ByteCode) } @@ -820,6 +819,7 @@ func TestProperty(t *testing.T) { OpProperty, OpReturn, OpReturn, + OpReturn, }, script.ByteCode) _, err = script.run(env, nil) @@ -855,6 +855,7 @@ func TestProperty(t *testing.T) { OpProperty, OpReturn, OpReturn, + OpReturn, OpRef, 255, 255, OpRef, 0, 205, @@ -893,9 +894,22 @@ 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())) + require.Equal(t, 2, len(rs.Calls())) // plus & eq require.Equal(t, rs.Result(), true) } diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index 4b6f28aa4c..da87ccf405 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -104,9 +104,6 @@ func (a CallSystemState) Return() Fsm { // skip right now } else { a.deferreds.Add(b, a.ns[i], fmt.Sprintf("sys %s param #%d", a.name, i)) - //a.c.set(ns[i], nil, nil, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i)) - //b.Write(a.params) - //a.b.ret() } } @@ -135,8 +132,8 @@ func (a CallSystemState) Write(_ params, b []byte) { if n, ok := isConstant(a.deferred[i]); ok { a.b.writeByte(OpRef) a.b.write(encode(n)) - a.b.writeByte(OpCache) - a.b.write(encode(n)) + //a.b.writeByte(OpCache) + //a.b.write(encode(n)) } else { n := a.ns[i] a.b.writeByte(OpRef) diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 18a5903d4f..4bc3342d07 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -10,12 +10,15 @@ type CallUserState struct { argc uint16 startedAt uint16 - deferred []Deferred deferreds Deferreds + ns []uniqueid } func (a CallUserState) backward(state Fsm) Fsm { - a.deferred = append(a.deferred, state.(Deferred)) + num := len(a.ns) + n := a.params.u.next() + a.ns = append(a.ns, n) + a.deferreds.Add(state.(Deferred), n, fmt.Sprintf("call user %s backward #%d", a.name, num)) return a } @@ -39,7 +42,8 @@ func (a CallUserState) Func(name string, args []string, invoke string) Fsm { } func (a CallUserState) Bytes(b []byte) Fsm { - a.deferred = append(a.deferred, a.constant(rideBytes(b))) + cons := a.constant(rideBytes(b)) + a.ns = append(a.ns, cons.n) return a } @@ -56,12 +60,14 @@ func (a CallUserState) FalseBranch() Fsm { } func (a CallUserState) String(s string) Fsm { - a.deferred = append(a.deferred, a.constant(rideString(s))) + cons := a.constant(rideString(s)) + a.ns = append(a.ns, cons.n) return a } func (a CallUserState) Boolean(v bool) Fsm { - a.deferred = append(a.deferred, a.constant(rideBoolean(v))) + cons := a.constant(rideBoolean(v)) + a.ns = append(a.ns, cons.n) return a } @@ -71,61 +77,22 @@ func (a CallUserState) Assigment(name string) Fsm { } func (a CallUserState) Long(value int64) Fsm { - a.deferred = append(a.deferred, a.constant(rideInt(value))) + cons := a.constant(rideInt(value)) + a.ns = append(a.ns, cons.n) return a } func (a CallUserState) Return() Fsm { - /* - // check user functions - n, ok := a.r.get(a.name) - if !ok { - panic(fmt.Sprintf("user function `%s` not found", a.name)) - } - for i, pos := range a.argn { - a.b.writeByte(OpSetArg) - funcParamID, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i)) - if !ok { - panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i))) - } - a.b.write(encode(pos)) - a.b.write(encode(funcParamID)) - } - - _, ok = a.params.c.get(n) - if !ok { - panic(fmt.Sprintf("no point %d found in cell", n)) - } - - //a.b.call(point.position, a.argc) - a.b.writeByte(OpRef) - a.b.write(encode(n)) - */ - return a.prev.backward(a) //.backward(a.startedAt, a.b.len()) + return a.prev.backward(a) } func (a CallUserState) Call(name string, argc uint16) Fsm { - //n := a.u.next() - //a.c.set(n, nil, nil, 0, false, fmt.Sprintf("function as paramentr: %s$%d", name, n)) - //a.argn = append(a.argn, n) - //if a.ret != nil { - // panic("already assigned") - //} - //a.ret = func(state CallUserState, startedAt uint16, endedAt uint16) { - // a.b.writeByte(OpCache) - // a.b.write(encode(n)) - // a.b.writeByte(OpPop) - //} return callTransition(a, a.params, name, argc, a.deferreds) } func (a CallUserState) Reference(name string) Fsm { - a.deferred = append(a.deferred, reference(a, a.params, name)) - //rs, ok := a.r.get(name) - //if !ok { - // panic("CallUserState Reference " + name + " not found") - //} - //a.argn = append(a.argn, rs) + cons := reference(a, a.params, name) + a.ns = append(a.ns, cons.n) return a } @@ -139,48 +106,14 @@ func (a CallUserState) Write(_ params, b []byte) { if !ok { panic(fmt.Sprintf("user function `%s` not found", a.name)) } - - if int(a.argc) != len(a.deferred) { - panic(fmt.Sprintf("argc %d != a.deferred %d", a.argc, len(a.deferred))) + if int(a.argc) != len(a.ns) { + panic(fmt.Sprintf("argc %d != a.ns %d", a.argc, len(a.ns))) } - - var ns []uniqueid - for i := uint16(0); i < a.argc; i++ { - if n, ok := isConstant(a.deferred[i]); ok { - a.b.writeByte(OpRef) - a.b.write(encode(n)) - a.b.writeByte(OpCache) - a.b.write(encode(n)) - //a.b.write(encode(fn + 1 + i)) - //a.b.writeByte(OpPop) - ns = append(ns, n) - } else { - n := a.u.next() - a.b.writeByte(OpRef) - a.b.write(encode(n)) - //a.b.writeByte(OpCache) - //a.b.write(encode(fn + 1 + i)) - //a.b.writeByte(OpPop) - ns = append(ns, n) - } + for _, n := range a.ns { + a.b.writeByte(OpRef) + a.b.write(encode(n)) } - a.b.writeByte(OpRef) a.b.write(encode(fn)) a.b.write(b) - a.b.ret() - - if len(ns) != len(a.deferred) { - panic(fmt.Sprintf("ns %d != a.deferred %d", a.argc, len(a.deferred))) - } - - for i, b := range a.deferred { - if _, ok := isConstant(b); ok { - // skip right now - } else { - a.c.set(ns[i], nil, 0, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i)) - b.Write(a.params, nil) - a.b.ret() - } - } } diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index ca9421acdc..cb4db3bc29 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -345,6 +345,11 @@ func (a constantDeferred) Write(p params, _ []byte) { func (a constantDeferred) Clean() { } +// +//func (a constantDeferred) N() uniqueid { +// return a.n +//} + func NewConstantDeferred(n uniqueid) constantDeferred { return constantDeferred{n: n} } diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index 24a9357c2a..c32d84e1b8 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -79,6 +79,7 @@ func (a MainState) Return() Fsm { } body[0].Write(a.params, nil) + a.b.ret() body = body[1:] if len(body) == 0 { break diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index f81974ceca..f2a11046de 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -80,7 +80,7 @@ func (a *params) constant(value rideType) constantDeferred { return NewConstantDeferred(n) } -func reference(_ Fsm, params params, name string) Deferred { +func reference(_ Fsm, params params, name string) constantDeferred { pos, ok := params.r.getAssigment(name) if !ok { panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) diff --git a/pkg/ride/result.go b/pkg/ride/result.go index 5f2a507e80..52ccc82d56 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -1,7 +1,6 @@ package ride import ( - "github.com/stretchr/testify/assert" "github.com/wavesplatform/gowaves/pkg/proto" ) @@ -83,7 +82,7 @@ func (r DAppResult) ScriptActions() proto.ScriptActions { func (r DAppResult) Eq(other RideResult) bool { switch v := other.(type) { case DAppResult: - return r.res == v.res && assert.ObjectsAreEqual(r.actions, v.actions) + return r.res == v.res && r.actions.Eq(v.actions) default: return false } diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index eda3be3891..1df1bcba6f 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -2,6 +2,7 @@ package ride import ( "github.com/pkg/errors" + "github.com/stretchr/testify/assert" "github.com/wavesplatform/gowaves/pkg/proto" "go.uber.org/zap" ) @@ -97,6 +98,17 @@ func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, zap.S().Error(i, txID, " ", "") } } + + ac1 := rs1.ScriptActions() + ac2 := rs2.ScriptActions() + for i := range ac1 { + zap.S().Errorf("%d %s Action %+v", i, txID, ac1[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value) + zap.S().Errorf("%d %s Action %+v", i, txID, ac2[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value) + zap.S().Errorf("Eq %+v", assert.ObjectsAreEqual(ac1[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value, ac2[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value)) + break + //zap.S().Errorf(i, txID, " Action ", ac2[i]) + } + return nil, errors.New("R1 != R2: failed to call account script on transaction ") } return rs2, nil diff --git a/pkg/ride/vm_estimator.go b/pkg/ride/vm_estimator.go new file mode 100644 index 0000000000..744c4a2370 --- /dev/null +++ b/pkg/ride/vm_estimator.go @@ -0,0 +1,20 @@ +package ride + +type VmEstimator struct { + //cost int + builtin map[string]int +} + +func NewVmEstimator(builtin map[string]int) *VmEstimator { + return &VmEstimator{ + builtin: builtin, + } +} + +func (a VmEstimator) Ref() int { + return 1 +} + +func (a VmEstimator) Builtin(n string) int { + return a.builtin[n] +} From 349c86360ff9b96cd6476486a3153123b5ed0df0 Mon Sep 17 00:00:00 2001 From: Frozen Date: Wed, 10 Mar 2021 14:38:48 +0300 Subject: [PATCH 39/55] Expanded tree. --- go.mod | 2 +- go.sum | 6 + pkg/ride/compiler2.go | 9 +- pkg/ride/compiler2_test.go | 26 +++ pkg/ride/compiler_assigment.go | 1 - pkg/ride/compiler_call_system.go | 6 +- pkg/ride/compiler_helpers.go | 6 +- pkg/ride/decompiler.go | 31 ++- pkg/ride/environment.go | 12 ++ pkg/ride/executable.go | 2 +- pkg/ride/functions_predefined.go | 18 ++ pkg/ride/tree.go | 107 ++++++++- pkg/ride/tree_evaluation.go | 4 +- pkg/ride/tree_evaluation_test.go | 20 ++ pkg/ride/tree_evaluator.go | 10 +- pkg/ride/tree_expand.go | 146 +++++++++++++ pkg/ride/tree_expand_test.go | 359 +++++++++++++++++++++++++++++++ pkg/ride/vm.go | 3 + pkg/state/scripts_storage.go | 6 +- 19 files changed, 754 insertions(+), 20 deletions(-) create mode 100644 pkg/ride/tree_expand.go create mode 100644 pkg/ride/tree_expand_test.go diff --git a/go.mod b/go.mod index 42ec4e405c..ae611d9daa 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 - github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b // indirect + github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4 github.com/fxamacker/cbor/v2 v2.2.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 diff --git a/go.sum b/go.sum index 454429caa3..718541bde3 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,12 @@ 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.0.0-20200831220546-14f58278114b h1:pxBLQ5mIlm4mKl2lx1IhwLhpAu2XhnDDn2a+ooAN8dU= github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= +github.com/frozen/immutable_map v0.0.0-20210224145525-b2feefc1f762 h1:5DnPrjV5ZRHl2jh+VVpnl0nR/in3AYP8j/6vWvKWzeE= +github.com/frozen/immutable_map v0.0.0-20210224145525-b2feefc1f762/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= +github.com/frozen/immutable_map v0.0.0-20210224161639-a72734704977 h1:ViTVPEPcu1DRvkN1WTIEiL6S7qXsgJGlKnZYpSnnSRo= +github.com/frozen/immutable_map v0.0.0-20210224161639-a72734704977/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= +github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4 h1:QJdN7XRRAp+ZEGl0ha5rjuL5/XJrEMtht0csVoVcvHA= +github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4/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= diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go index 6b9734da37..4808996fab 100644 --- a/pkg/ride/compiler2.go +++ b/pkg/ride/compiler2.go @@ -4,6 +4,7 @@ import ( "math" "github.com/pkg/errors" + "go.uber.org/zap" ) func ccc(f Fsm, node Node) (Fsm, error) { @@ -82,7 +83,13 @@ func CompileVerifier(txID string, tree *Tree) (*Executable, error) { return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, tree.IsDApp(), tree.HasVerifier()) } -func CompileDapp(txID string, tree *Tree) (*Executable, error) { +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") + } + }() if !tree.IsDApp() { return nil, errors.Errorf("unable to compile dappp") } diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 770bec3ef5..3099599605 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -44,6 +44,9 @@ var defaultEnv = &MockRideEnvironment{ invocationFunc: func() rideObject { return rideObject{} }, + heightFunc: func() rideInt { + return rideInt(100500) + }, } func Test22(t *testing.T) { @@ -1488,3 +1491,26 @@ func Test111111(t *testing.T) { t.Log(i, " ", c) } } + +/** +let height = height +height != 0 +*/ +func TestShadowedVariable(t *testing.T) { + 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 = { height }; height != 0)", DecompileTree(tree)) + + script, err := CompileTree("", tree) + require.NoError(t, err) + + rs, err := script.Verify(defaultEnv) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) +} diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 133577dc33..4d05bec1c5 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -57,7 +57,6 @@ func (a AssigmentState) Boolean(v bool) Fsm { } func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid, d Deferreds) Fsm { - params.r.setAssigment(name, n) return newAssigmentFsm(prev, params, name, n, d) } diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index da87ccf405..fc74077c0e 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -132,20 +132,16 @@ func (a CallSystemState) Write(_ params, b []byte) { if n, ok := isConstant(a.deferred[i]); ok { a.b.writeByte(OpRef) a.b.write(encode(n)) - //a.b.writeByte(OpCache) - //a.b.write(encode(n)) } else { n := a.ns[i] a.b.writeByte(OpRef) a.b.write(encode(n)) - //a.b.writeByte(OpCache) - //a.b.write(encode(n)) } } n, ok := a.f(a.name) if !ok { - panic(fmt.Sprintf("system function named `%s` not found", a.name)) + panic(fmt.Sprintf("%s system function named `%s` not found", a.params.txID, a.name)) } a.b.externalCall(n, a.argc) } diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index cb4db3bc29..a6cbb2e78a 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -157,6 +157,7 @@ func (a point) Serialize(s Serializer) error { } s.Uint16(a.fn) + s.String(a.debugInfo) return nil } @@ -171,7 +172,6 @@ func deserializePoint(d *Deserializer) (point, error) { if err != nil { return a, err } - a.value, err = d.RideValue() if err != nil { return a, err @@ -180,6 +180,10 @@ func deserializePoint(d *Deserializer) (point, error) { if err != nil { return a, err } + a.debugInfo, err = d.String() + if err != nil { + return a, err + } return a, nil } diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index abd899eaa8..49462a621f 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -37,6 +37,13 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d f(s, nodes[1]) s.WriteString(")") }, + "!=": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + s.WriteString("(") + f(s, nodes[0]) + s.WriteString(" != ") + f(s, nodes[1]) + s.WriteString(")") + }, "100": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, "+", nodes, f) }, @@ -82,6 +89,9 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "420": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "toString", nodes, f) }, + "500": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "sigVerify", nodes, f) + }, "504": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "rsaVerify", nodes, f) }, @@ -94,6 +104,9 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "2": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "throw", nodes, f) }, + "1050": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + prefix(s, "getInteger", nodes, f) + }, "1052": func(s *strings.Builder, name string, nodes []Node, f detreeType) { prefix(s, "getBinary", nodes, f) }, @@ -118,6 +131,18 @@ func defunc(s *strings.Builder, name string, nodes []Node, f detreeType) { } } +func DecompileTree(t *Tree) string { + var s strings.Builder + for _, v := range t.Declarations { + s.WriteString(Decompiler(v)) + } + for _, v := range t.Functions { + s.WriteString(Decompiler(v)) + } + s.WriteString(Decompiler(t.Verifier)) + return strings.TrimSpace(s.String()) +} + func Decompiler(tree Node) string { s := &strings.Builder{} detree(s, tree) @@ -128,7 +153,7 @@ func detree(s *strings.Builder, tree Node) { switch n := tree.(type) { case *FunctionDeclarationNode: if n.invocationParameter != "" { - s.WriteString("@" + n.invocationParameter + "@") + s.WriteString("@" + n.invocationParameter + "\\n") } s.WriteString(fmt.Sprintf("func %s(", n.Name)) for i, a := range n.Arguments { @@ -142,9 +167,9 @@ func detree(s *strings.Builder, tree Node) { s.WriteString(" } ") detree(s, n.Block) case *AssignmentNode: - s.WriteString(fmt.Sprintf("let %s = ", n.Name)) + s.WriteString(fmt.Sprintf("let %s = { ", n.Name)) detree(s, n.Expression) - s.WriteString("; ") + s.WriteString(" }; ") detree(s, n.Block) case *ConditionalNode: s.WriteString(fmt.Sprintf("if (")) diff --git a/pkg/ride/environment.go b/pkg/ride/environment.go index f96da2847f..b4b1c98f8b 100644 --- a/pkg/ride/environment.go +++ b/pkg/ride/environment.go @@ -150,3 +150,15 @@ func (e *Environment) checkMessageLength(l int) bool { func (e *Environment) invocation() rideObject { return e.inv } + +func (e *Environment) functions(libVersion int) (Functions, error) { + functions, err := selectFunctions(libVersion) + if err != nil { + return nil, err + } + provider, err := selectFunctionNameProvider(libVersion) + if err != nil { + return nil, err + } + return functionsImpl{f: functions, p: provider}, nil +} diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 3c07c721b5..6a9f5e9ed9 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -66,7 +66,7 @@ func (a *Executable) runWithoutChecks(environment RideEnvironment, name string, } v, err := vm.run() if err != nil { - return ScriptResult{res: false, msg: "", calls: vm.calls, refs: vm.ref}, err + return ScriptResult{res: false, msg: "", calls: vm.calls, refs: vm.ref, operations: vm.numOperations}, err } switch tv := v.(type) { case rideThrow: diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index c894cbbf0f..92e95bd33a 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -63,3 +63,21 @@ func init() { predefined.set(v.name, uint16(math.MaxUint16-k), v.f) } } + +type Functions interface { + function(int) rideFunction + name(int) string +} + +type functionsImpl struct { + f func(id int) rideFunction + p func(int) string +} + +func (a functionsImpl) function(v int) rideFunction { + return a.f(v) +} + +func (a functionsImpl) name(v int) string { + return a.p(v) +} diff --git a/pkg/ride/tree.go b/pkg/ride/tree.go index e24ee832d9..fd599be79d 100644 --- a/pkg/ride/tree.go +++ b/pkg/ride/tree.go @@ -3,6 +3,7 @@ package ride type Node interface { node() SetBlock(node Node) + Clone() Node } type LongNode struct { @@ -13,6 +14,10 @@ func (*LongNode) node() {} func (*LongNode) SetBlock(Node) {} +func (a *LongNode) Clone() Node { + return &*a +} + func NewLongNode(v int64) *LongNode { return &LongNode{Value: v} } @@ -25,6 +30,11 @@ func (*BytesNode) node() {} func (*BytesNode) SetBlock(Node) {} +func (a *BytesNode) Clone() Node { + // Bytes references to the same location, but it makes no sense to modify them. + return &*a +} + func NewBytesNode(v []byte) *BytesNode { return &BytesNode{Value: v} } @@ -37,6 +47,10 @@ func (*StringNode) node() {} func (*StringNode) SetBlock(Node) {} +func (a *StringNode) Clone() Node { + return &*a +} + func NewStringNode(v string) *StringNode { return &StringNode{Value: v} } @@ -49,6 +63,10 @@ func (*BooleanNode) node() {} func (*BooleanNode) SetBlock(Node) {} +func (a *BooleanNode) Clone() Node { + return &*a +} + func NewBooleanNode(v bool) *BooleanNode { return &BooleanNode{Value: v} } @@ -63,6 +81,14 @@ func (*ConditionalNode) node() {} func (*ConditionalNode) SetBlock(Node) {} +func (a *ConditionalNode) Clone() Node { + return &ConditionalNode{ + Condition: a.Condition.Clone(), + TrueExpression: a.TrueExpression.Clone(), + FalseExpression: a.FalseExpression.Clone(), + } +} + func NewConditionalNode(condition, trueExpression, falseExpression Node) *ConditionalNode { return &ConditionalNode{ Condition: condition, @@ -79,8 +105,16 @@ type AssignmentNode struct { func (*AssignmentNode) node() {} -func (n *AssignmentNode) SetBlock(node Node) { - n.Block = node +func (a *AssignmentNode) SetBlock(node Node) { + a.Block = node +} + +func (a *AssignmentNode) Clone() Node { + return &AssignmentNode{ + Name: a.Name, + Expression: a.Expression.Clone(), + Block: a.Block.Clone(), + } } func NewAssignmentNode(name string, expression, block Node) *AssignmentNode { @@ -99,6 +133,10 @@ func (*ReferenceNode) node() {} func (*ReferenceNode) SetBlock(Node) {} +func (a *ReferenceNode) Clone() Node { + return &ReferenceNode{Name: a.Name} +} + func NewReferenceNode(name string) *ReferenceNode { return &ReferenceNode{Name: name} } @@ -117,6 +155,36 @@ func (n *FunctionDeclarationNode) SetBlock(node Node) { n.Block = node } +func clone(n Node) Node { + if n == nil { + return n + } + return n.Clone() +} + +func cloneFuncDecl(n *FunctionDeclarationNode, body Node, block Node) *FunctionDeclarationNode { + return &FunctionDeclarationNode{ + Name: n.Name, + Arguments: n.Arguments, + Body: body, + Block: block, + invocationParameter: n.invocationParameter, + } +} + +func (n *FunctionDeclarationNode) Clone() Node { + args := make([]string, len(n.Arguments)) + copy(args, n.Arguments) + + return &FunctionDeclarationNode{ + Name: n.Name, + Arguments: args, + Body: n.Body.Clone(), + Block: clone(n.Block), + invocationParameter: n.invocationParameter, + } +} + func NewFunctionDeclarationNode(name string, arguments []string, body, block Node) *FunctionDeclarationNode { return &FunctionDeclarationNode{ Name: name, @@ -126,9 +194,27 @@ func NewFunctionDeclarationNode(name string, arguments []string, body, block Nod } } +type Nodes []Node + +func (a Nodes) Clone() Nodes { + out := make(Nodes, 0, len(a)) + for _, v := range a { + out = append(out, v.Clone()) + } + return out +} + +func (a Nodes) Map(f func(Node) Node) Nodes { + args := make([]Node, 0, len(a)) + for _, v := range a { + args = append(args, f(v)) + } + return args +} + type FunctionCallNode struct { Name string - Arguments []Node + Arguments Nodes } func (a *FunctionCallNode) ArgumentsCount() uint16 { @@ -139,6 +225,13 @@ func (*FunctionCallNode) node() {} func (*FunctionCallNode) SetBlock(Node) {} +func (a *FunctionCallNode) Clone() Node { + return &FunctionCallNode{ + Name: a.Name, + Arguments: a.Arguments.Clone(), + } +} + func NewFunctionCallNode(name string, arguments []Node) *FunctionCallNode { return &FunctionCallNode{ Name: name, @@ -155,6 +248,13 @@ func (*PropertyNode) node() {} func (*PropertyNode) SetBlock(Node) {} +func (a *PropertyNode) Clone() Node { + return &PropertyNode{ + Name: a.Name, + Object: a.Object.Clone(), + } +} + func NewPropertyNode(name string, object Node) *PropertyNode { return &PropertyNode{ Name: name, @@ -176,6 +276,7 @@ type Tree struct { Declarations []Node Functions []Node Verifier Node + Expanded bool } func (t *Tree) HasVerifier() bool { diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 1df1bcba6f..8f30948be7 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -25,11 +25,11 @@ func CallVmVerifier(txID string, env RideEnvironment, compiled *Executable) (Rid func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) (RideResult, error) { r, err := CallVmVerifier(txID, env, exe) if err != nil { - return nil, err + return nil, errors.Wrap(err, "vm verifier") } r2, err := CallTreeVerifier(env, tree) if err != nil { - return nil, err + return nil, errors.Wrap(err, "tree verifier") } if !r.Eq(r2) { diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 3f4b344cdc..8ff628051e 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -3514,3 +3514,23 @@ func TestInvalidAssetInTransferScriptAction(t *testing.T) { } assert.Equal(t, expectedResult, sr) } + +/** +let height = height +height != 0 +*/ +func TestTreeShadowedVariable(t *testing.T) { + 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 = { height }; height != 0)", DecompileTree(tree)) + + result, err := CallTreeVerifier(defaultEnv, tree) + require.NoError(t, err) + require.Equal(t, true, result.Result()) +} diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index 1ba4397c42..76b93aacb1 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -5,6 +5,9 @@ import ( "github.com/wavesplatform/gowaves/pkg/proto" ) +type evaluationCtx struct { +} + type esConstant struct { value rideType c rideConstructor @@ -14,6 +17,7 @@ type esValue struct { id string value rideType expression Node + size int } type esFunction struct { @@ -44,9 +48,13 @@ func (s *evaluationScope) declare(n Node) error { } func (s *evaluationScope) pushExpression(id string, n Node) { - s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, expression: n}) + s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, expression: n, size: len(s.cs[len(s.cs)-1])}) } +//func (s *evaluationScope) pushExpression2(id string, n Node, ctx evaluationCtx) evaluationCtx { +// +//} + func (s *evaluationScope) pushValue(id string, v rideType) { s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, value: v}) } diff --git a/pkg/ride/tree_expand.go b/pkg/ride/tree_expand.go new file mode 100644 index 0000000000..9d7a287f8c --- /dev/null +++ b/pkg/ride/tree_expand.go @@ -0,0 +1,146 @@ +package ride + +import ( + "fmt" + + im "github.com/frozen/immutable_map" + "github.com/pkg/errors" +) + +type expandScope struct { + im *im.Map +} + +func newExpandScope() expandScope { + return expandScope{ + im: im.New(), + } +} + +func (a expandScope) add(name string, n *FunctionDeclarationNode) expandScope { + return expandScope{ + im: a.im.Insert([]byte(name), n), + } +} + +func (a expandScope) get(name string) (*FunctionDeclarationNode, bool) { + v, ok := a.im.Get([]byte(name)) + if ok { + return v.(*FunctionDeclarationNode), true + } + return nil, false +} + +func (a expandScope) get1(name string) *FunctionDeclarationNode { + v, ok := a.im.Get([]byte(name)) + if ok { + return v.(*FunctionDeclarationNode) + } + return nil +} + +func Expand(t *Tree) (*Tree, error) { + if t.Expanded { + return t, nil + } + scope := newExpandScope() + declarations := make([]Node, 0, len(t.Declarations)) + for _, f := range t.Declarations { + v, ok := f.(*FunctionDeclarationNode) + if !ok { + declarations = append(declarations, expand(scope, f)) + continue + } + v2 := cloneFuncDecl(v, expand(scope, v.Body), nil) + scope = scope.add(v.Name, v2) + } + functions := make([]Node, 0, len(t.Functions)) + for _, f := range t.Functions { + v, ok := f.(*FunctionDeclarationNode) + if !ok { + return nil, errors.Errorf("can't expand tree. Expected function to be `*FunctionDeclarationNode`, found %T", f) + } + v2 := v.Clone().(*FunctionDeclarationNode) + v2.Body = expand(scope, v.Body) + scope = scope.add(v.Name, v2) + functions = append(functions, v2) + } + verifier := t.Verifier + if t.IsDApp() && t.HasVerifier() { + verifier = cloneFuncDecl(t.Verifier.(*FunctionDeclarationNode), expand(scope, t.Verifier.(*FunctionDeclarationNode).Body), nil) + } else { + verifier = expand(scope, t.Verifier) + } + return &Tree{ + Digest: t.Digest, + AppVersion: t.AppVersion, + LibVersion: t.LibVersion, + HasBlockV2: t.HasBlockV2, + Meta: t.Meta, + Declarations: declarations, + Functions: functions, + Verifier: verifier, + Expanded: true, + }, nil +} + +func MustExpand(t *Tree) *Tree { + rs, err := Expand(t) + if err != nil { + panic(err) + } + return rs +} + +func expand(scope expandScope, node Node) Node { + switch v := node.(type) { + case *FunctionCallNode: + f, ok := scope.get(v.Name) + if ok { + root := f.Body + for i := len(v.Arguments) - 1; i >= 0; i-- { + root = &AssignmentNode{ + Name: f.Arguments[i], + Expression: expand(scope, v.Arguments[i]), + Block: root, + } + } + return root + } else { + return &FunctionCallNode{ + Name: v.Name, + Arguments: v.Arguments.Map(func(node Node) Node { + return expand(scope, node) + }), + } + } + + case *FunctionDeclarationNode: + body := expand(scope, v.Body) + v2 := cloneFuncDecl(v, body, nil) + block := expand(scope.add(v.Name, v2), v.Block) + return block + + case *AssignmentNode: + return &AssignmentNode{ + Name: v.Name, + Block: expand(scope, v.Block), + Expression: expand(scope, v.Expression), + } + case nil: + return node + case *ConditionalNode: + return &ConditionalNode{ + Condition: expand(scope, v.Condition), + TrueExpression: expand(scope, v.TrueExpression), + FalseExpression: expand(scope, v.FalseExpression), + } + case *ReferenceNode: + return v + case *StringNode, *LongNode, *BytesNode, *BooleanNode, *PropertyNode: + return v + default: + panic(fmt.Sprintf("unknown %T", node)) + return v.Clone() + } +} diff --git a/pkg/ride/tree_expand_test.go b/pkg/ride/tree_expand_test.go new file mode 100644 index 0000000000..db24bcfa9c --- /dev/null +++ b/pkg/ride/tree_expand_test.go @@ -0,0 +1,359 @@ +package ride + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "github.com/wavesplatform/gowaves/pkg/proto" + + //"github.com/wavesplatform/gowaves/pkg/proto" + "github.com/wavesplatform/gowaves/pkg/types" +) + +func lines(ss ...string) string { + var s strings.Builder + for _, v := range ss { + s.WriteString(v) + s.WriteString(" ") + } + return strings.TrimSpace(s.String()) +} + +func TestTreeExpand(t *testing.T) { + source := `AAIDAAAAAAAAAAgIARIECgIIAgAAAAEBAAAAAmYyAAAAAAkBAAAABXZhbHVlAAAAAQkABBoAAAACBQAAAAR0aGlzAgAAAAF4AAAAAQAAAAFpAQAAAAJmMQAAAAIAAAAJc2Vzc2lvbklkAAAAB3JzYVNpZ24EAAAAAXgJAQAAAAJmMgAAAAAJAQAAAAhXcml0ZVNldAAAAAEFAAAAA25pbAAAAADvU/gM` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + tree2, _ := Expand(tree) + + require.Equal(t, + `@i\nfunc f1(sessionId,rsaSign) { let x = { value(getInteger(this,"x")) }; WriteSet(nil) }`, + DecompileTree(tree2), + ) +} + +func TestTreeExpandWithArguments(t *testing.T) { + source := `AAIDAAAAAAAAAAgIARIECgIIAgAAAAIAAAAAAXoAAAAAAAAAAAUBAAAAAmYyAAAAAQAAAAF2CQEAAAAFdmFsdWUAAAABCQAEGgAAAAIFAAAABHRoaXMFAAAAAXYAAAABAAAAAWkBAAAAAmYxAAAAAgAAAAlzZXNzaW9uSWQAAAAHcnNhU2lnbgQAAAABeAkBAAAAAmYyAAAAAQIAAAABZQkBAAAACFdyaXRlU2V0AAAAAQUAAAADbmlsAAAAAN+I8mI=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + tree2, _ := Expand(tree) + + require.Equal(t, + lines( + `let z = { 5 };`, + `@i\nfunc f1(sessionId,rsaSign) { let x = { let v = { "e" }; value(getInteger(this,v)) }; WriteSet(nil) }`, + ), + DecompileTree(tree2), + ) +} + +/** +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} +func f2() = { + 5 +} + +@Callable(i) +func f1 () = { + WriteSet([DataEntry("key", f2())]) +} + +*/ +func TestTreeExpandAsArgument(t *testing.T) { + source := `AAIDAAAAAAAAAAQIARIAAAAAAQEAAAACZjIAAAAAAAAAAAAAAAAFAAAAAQAAAAFpAQAAAAJmMQAAAAAJAQAAAAhXcml0ZVNldAAAAAEJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAAA2tleQkBAAAAAmYyAAAAAAUAAAADbmlsAAAAABmdzZY=` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + tree2, _ := Expand(tree) + + require.Equal(t, + `@i\nfunc f1() { WriteSet(1100(DataEntry("key",5),nil)) }`, + DecompileTree(tree2), + ) +} + +/** +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} +func call(v: Int) = { + func f2() = { + 10 + } + f2() +} + +func f2() = { + 5 +} + +@Callable(i) +func callback () = { + let x = call(0) + WriteSet([DataEntry("key", f2())]) +} +*/ +func TestTreeExpandWithNamesIntersection(t *testing.T) { + source := `AAIDAAAAAAAAAAQIARIAAAAAAgEAAAAEY2FsbAAAAAEAAAABdgoBAAAAAmYyAAAAAAAAAAAAAAAACgkBAAAAAmYyAAAAAAEAAAACZjIAAAAAAAAAAAAAAAAFAAAAAQAAAAFpAQAAAAhjYWxsYmFjawAAAAAEAAAAAXgJAQAAAARjYWxsAAAAAQAAAAAAAAAAAAkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAADa2V5CQEAAAACZjIAAAAABQAAAANuaWwAAAAA/C/YQQ==` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + tree2, _ := Expand(tree) + + require.Equal(t, + `@i\nfunc callback() { let x = { let v = { 0 }; 10 }; WriteSet(1100(DataEntry("key",5),nil)) }`, + DecompileTree(tree2), + ) +} + +func TestTreeExpand11(t *testing.T) { + t.Run("expand with variable and func name collision", func(t *testing.T) { + /** + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# 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) + + tree, err := Parse(src) + require.NoError(t, err) + + tree2, _ := Expand(tree) + + require.Equal(t, + `(let inc = { 2 }; let v = { inc }; (v + 1) == 3)`, + DecompileTree(tree2), + ) + rs, err := CallTreeVerifier(nil, tree2) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) + }) + t.Run("expand 2 funcs", func(t *testing.T) { + /** + {-# STDLIB_VERSION 3 #-} + {-# SCRIPT_TYPE ACCOUNT #-} + {-# CONTENT_TYPE EXPRESSION #-} + func inc() = true + func call() = { + inc() + } + call() + */ + source := `AwoBAAAAA2luYwAAAAAGCgEAAAAEY2FsbAAAAAAJAQAAAANpbmMAAAAACQEAAAAEY2FsbAAAAAByJ2Mb` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + tree2, _ := Expand(tree) + + require.Equal(t, + `true`, + DecompileTree(tree2), + ) + rs, err := CallTreeVerifier(nil, tree2) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) + }) + + t.Run("", func(t *testing.T) { + + }) +} + +/** +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE EXPRESSION #-} +func f2() = { + 5 +} +f2() == f2() +*/ +func TestTreeExpandExpression(t *testing.T) { + source := `AwoBAAAAAmYyAAAAAAAAAAAAAAAABQkAAAAAAAACCQEAAAACZjIAAAAACQEAAAACZjIAAAAAIckc5A==` + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + + tree2, _ := Expand(tree) + + require.Equal(t, + `(5 == 5)`, + DecompileTree(tree2), + ) +} + +func TestExpandScope(t *testing.T) { + m := newExpandScope(). + add("inc", &FunctionDeclarationNode{Name: "inc"}). + add("call", &FunctionDeclarationNode{Name: "call"}) + + require.NotNil(t, m.get1("call")) +} + +func TestExpandSmthWrote(t *testing.T) { + // file_5.ride + //source := `AAIDAAAAAAAAAAQIARIAAAAAIgEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBoAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAEAAAAOZ2V0U3RyaW5nQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABB0AAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABlN0cmluZwQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQIAAAAAAQAAAAxnZXRCb29sQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBsAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAB0Jvb2xlYW4EAAAAAWEFAAAAByRtYXRjaDAFAAAAAWEHAQAAABhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkAAAACAAAAB2FkZHJlc3MAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAAB2FkZHJlc3MFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAAAQAAABZjb252ZXJ0SnNvbkFycmF5VG9MaXN0AAAAAQAAAAlqc29uQXJyYXkJAAS1AAAAAgUAAAAJanNvbkFycmF5AgAAAAEsAAAAAAVCTE9DSwIAAAAFYmxvY2sAAAAACUNPTkZJUk1UWAIAAAAKY29uZmlybV90eAAAAAAKT3JhY2xlc0tleQIAAAAHb3JhY2xlcwAAAAAJQWRtaW5zS2V5AgAAAAZhZG1pbnMAAAAAD1ZvdGVJbnRlcnZhbEtleQIAAAANdm90ZV9pbnRlcnZhbAAAAAAUQ29lZmZpY2llbnRPcmFjbGVLZXkCAAAAEmNvZWZmaWNpZW50X29yYWNsZQAAAAATQ29lZmZpY2llbnRBZG1pbktleQIAAAARY29lZmZpY2llbnRfYWRtaW4AAAAADlByaWNlT2Zmc2V0S2V5AgAAAAxwcmljZV9vZmZzZXQAAAAACFByaWNlS2V5AgAAAAVwcmljZQAAAAAMSXNCbG9ja2VkS2V5AgAAAAppc19ibG9ja2VkAAAAABJCbG9ja0V4cGlyZVZvdGVLZXkCAAAAEXZvdGVfZXhwaXJlX2Jsb2NrAAAAAA1QcmljZUluZGV4S2V5AgAAAAtwcmljZV9pbmRleAAAAAAQTGFzdENvbmZpcm1UeEtleQIAAAAPbGFzdF9jb25maXJtX3R4AQAAAA9nZXRBZG1pblZvdGVLZXkAAAABAAAABW93bmVyCQABLAAAAAICAAAAC2FkbWluX3ZvdGVfBQAAAAVvd25lcgEAAAAYZ2V0QWRtaW5Wb3RlQXJndW1lbnRzS2V5AAAAAQAAAAVvd25lcgkAASwAAAACCQABLAAAAAICAAAADHZvdGVfYWN0aW9uXwUAAAAFb3duZXICAAAACl9hcmd1bWVudHMBAAAAFWdldEJsYWNrU3dhcm1QcmljZUtleQAAAAEAAAAFYmxvY2sJAAEsAAAAAgkAASwAAAACAgAAABFibGFja19zd2FybV9wcmljZQIAAAABXwkAAaQAAAABBQAAAAVibG9jawEAAAASZ2V0UHJpY2VIaXN0b3J5S2V5AAAAAQAAAAVibG9jawkAASwAAAACCQABLAAAAAIFAAAACFByaWNlS2V5AgAAAAFfCQABpAAAAAEFAAAABWJsb2NrAQAAABhnZXRIZWlnaHRQcmljZUJ5SW5kZXhLZXkAAAABAAAABWluZGV4CQABLAAAAAIJAAEsAAAAAgUAAAANUHJpY2VJbmRleEtleQIAAAABXwkAAaQAAAABBQAAAAVpbmRleAEAAAAYZ2V0T3JhY2xlUHJvdmlkZVByaWNlS2V5AAAAAQAAAAZoZWlnaHQJAAEsAAAAAgIAAAAGcHJpY2VfCQABpAAAAAEFAAAABmhlaWdodAAAAAAFcHJpY2UJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEFAAAACFByaWNlS2V5AAAAAApwcmljZUluZGV4CQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABBQAAAA1QcmljZUluZGV4S2V5AAAAAAlpc0Jsb2NrZWQJAQAAAAxnZXRCb29sQnlLZXkAAAABBQAAAAxJc0Jsb2NrZWRLZXkAAAAAFGJmdENvZWZmaWNpZW50T3JhY2xlCQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABBQAAABRDb2VmZmljaWVudE9yYWNsZUtleQAAAAAScGVyY2VudFByaWNlT2Zmc2V0CQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABBQAAAA5QcmljZU9mZnNldEtleQAAAAAHb3JhY2xlcwkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQUAAAAKT3JhY2xlc0tleQAAAAALb3JhY2xlc0xpc3QJAQAAABZjb252ZXJ0SnNvbkFycmF5VG9MaXN0AAAAAQUAAAAHb3JhY2xlcwAAAAANbGFzdENvbmZpcm1UeAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQUAAAAQTGFzdENvbmZpcm1UeEtleQEAAAAWZ2V0T3JhY2xlUHJvdmlkZUhlaWdodAAAAAIAAAAFb3duZXIAAAAGaGVpZ2h0CQEAAAAYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AAAAAgkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABBQAAAAVvd25lcgkBAAAAGGdldE9yYWNsZVByb3ZpZGVQcmljZUtleQAAAAEFAAAABmhlaWdodAEAAAAPZ2V0UHJpY2VIaXN0b3J5AAAAAQAAAAZoZWlnaHQJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEJAQAAABJnZXRQcmljZUhpc3RvcnlLZXkAAAABBQAAAAZoZWlnaHQAAAABAAAAAWkBAAAAFGZpbmFsaXplQ3VycmVudFByaWNlAAAAAAQAAAAGcHJpY2VzCQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAAUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAQUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAgUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAwUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAABAUAAAAGaGVpZ2h0BQAAAANuaWwEAAAAE3ByaWNlUHJvdmlkaW5nQ291bnQJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAABkAAAAAgMJAQAAAAIhPQAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAwkBAAAAAiE9AAAAAgkAAZEAAAACBQAAAAZwcmljZXMAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAADCQEAAAACIT0AAAACCQABkQAAAAIFAAAABnByaWNlcwAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAMJAQAAAAIhPQAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAwkBAAAAAiE9AAAAAgkAAZEAAAACBQAAAAZwcmljZXMAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAEAAAACHByaWNlU3VtCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAAACQABkQAAAAIFAAAABnByaWNlcwAAAAAAAAAAAQkAAZEAAAACBQAAAAZwcmljZXMAAAAAAAAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAADCQABkQAAAAIFAAAABnByaWNlcwAAAAAAAAAABAQAAAAIbmV3UHJpY2UJAABpAAAAAgUAAAAIcHJpY2VTdW0FAAAAE3ByaWNlUHJvdmlkaW5nQ291bnQDBQAAAAlpc0Jsb2NrZWQJAAACAAAAAQIAAAATY29udHJhY3QgaXMgYmxvY2tlZAMJAQAAAAIhPQAAAAIJAQAAAA9nZXRQcmljZUhpc3RvcnkAAAABBQAAAAZoZWlnaHQAAAAAAAAAAAAJAAACAAAAAQIAAAAPd2FpdCBuZXh0IGJsb2NrAwkAAGYAAAACBQAAABRiZnRDb2VmZmljaWVudE9yYWNsZQUAAAATcHJpY2VQcm92aWRpbmdDb3VudAkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABpAAAAAEFAAAAFGJmdENvZWZmaWNpZW50T3JhY2xlAgAAACAvNSBvcmFjbGVzIG5lZWQgdG8gc2V0IGEgcHJpY2UgKAkAAaQAAAABBQAAABNwcmljZVByb3ZpZGluZ0NvdW50AgAAAAEpAwMJAABnAAAAAgUAAAAIbmV3UHJpY2UJAABkAAAAAgUAAAAFcHJpY2UJAABpAAAAAgkAAGgAAAACBQAAAAVwcmljZQUAAAAScGVyY2VudFByaWNlT2Zmc2V0AAAAAAAAAABkBgkAAGcAAAACCQAAZQAAAAIFAAAABXByaWNlCQAAaQAAAAIJAABoAAAAAgUAAAAFcHJpY2UFAAAAEnBlcmNlbnRQcmljZU9mZnNldAAAAAAAAAAAZAUAAAAIbmV3UHJpY2UJAQAAAAhXcml0ZVNldAAAAAEJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIFAAAADElzQmxvY2tlZEtleQYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIJAQAAABVnZXRCbGFja1N3YXJtUHJpY2VLZXkAAAABBQAAAAZoZWlnaHQFAAAACG5ld1ByaWNlBQAAAANuaWwEAAAADW5ld1ByaWNlSW5kZXgJAABkAAAAAgUAAAAKcHJpY2VJbmRleAAAAAAAAAAAAQkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAIUHJpY2VLZXkFAAAACG5ld1ByaWNlCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACCQEAAAASZ2V0UHJpY2VIaXN0b3J5S2V5AAAAAQUAAAAGaGVpZ2h0BQAAAAhuZXdQcmljZQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAANUHJpY2VJbmRleEtleQUAAAANbmV3UHJpY2VJbmRleAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkBAAAAGGdldEhlaWdodFByaWNlQnlJbmRleEtleQAAAAEFAAAADW5ld1ByaWNlSW5kZXgFAAAABmhlaWdodAUAAAADbmlsAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAAAAAAACBQAAAA1sYXN0Q29uZmlybVR4CQACWAAAAAEIBQAAAAJ0eAAAAAJpZK4nr/0=` + source := `AAIDAAAAAAAAAAQIARIAAAAAAwEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABAAAAA2tleQMJAAAAAAAAAgUAAAADa2V5AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAEmdldFByaWNlSGlzdG9yeUtleQAAAAEAAAAFYmxvY2sJAAEsAAAAAgIAAAAGcHJpY2VfCQABpAAAAAEFAAAABWJsb2NrAQAAAA9nZXRQcmljZUhpc3RvcnkAAAABAAAABmhlaWdodAkBAAAADmdldE51bWJlckJ5S2V5AAAAAQkBAAAAEmdldFByaWNlSGlzdG9yeUtleQAAAAEFAAAABmhlaWdodAAAAAEAAAABaQEAAAAUZmluYWxpemVDdXJyZW50UHJpY2UAAAAAAwkBAAAAAiE9AAAAAgkBAAAAD2dldFByaWNlSGlzdG9yeQAAAAEFAAAABmhlaWdodAAAAAAAAAAAAAkAAAIAAAABAgAAAA93YWl0IG5leHQgYmxvY2sJAQAAAAhXcml0ZVNldAAAAAEFAAAAA25pbAAAAACFlzmA` + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + tree = MustExpand(tree) + t.Log(DecompileTree(tree)) + require.NoError(t, err) + require.NotNil(t, tree) + + script, err := CompileDapp("", tree) + require.NoError(t, err) + require.NotNil(t, script) + this := []byte{1, 83, 0, 150, 158, 207, 181, 8, 55, 66, 81, 31, 197, 85, 116, 80, 81, 99, 170, 84, 137, 245, 151, 194, 97, 213} + + state := &MockSmartState{ + //NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + // return byte_helpers.TransferWithProofs.Transaction, nil + //} + // 1050 + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + // 2 + if bytes.Equal([]byte{1, 83, 0, 150, 158, 207, 181, 8, 55, 66, 81, 31, 197, 85, 116, 80, 81, 99, 170, 84, 137, 245, 151, 194, 97, 213}, account.Address.Bytes()) && key == "coefficient_oracle" { + return &proto.IntegerDataEntry{Key: key, Value: 3}, nil + } + // 11 + if bytes.Equal([]byte{1, 83, 116, 45, 101, 110, 53, 200, 52, 21, 10, 84, 172, 243, 171, 35, 86, 210, 136, 52, 119, 25, 63, 230, 32, 147}, account.Address.Bytes()) && key == "price_209553" { + return &proto.IntegerDataEntry{Key: key, Value: 60}, nil + } + // 17 + if bytes.Equal([]byte{1, 83, 15, 138, 8, 31, 66, 12, 76, 206, 150, 15, 215, 66, 227, 143, 47, 204, 196, 97, 159, 62, 62, 71, 220, 58}, account.Address.Bytes()) && key == "price_209553" { + return &proto.IntegerDataEntry{Key: key, Value: 60}, nil + } + // 23 + if bytes.Equal([]byte{1, 83, 59, 25, 51, 179, 38, 169, 228, 134, 63, 30, 65, 161, 51, 193, 50, 252, 107, 192, 198, 211, 1, 181, 85, 155}, account.Address.Bytes()) && key == "price_209553" { + return &proto.IntegerDataEntry{Key: key, Value: 60}, nil + } + // 29 + if bytes.Equal([]byte{1, 83, 136, 55, 96, 43, 245, 23, 100, 121, 143, 9, 41, 146, 104, 231, 155, 80, 89, 107, 191, 124, 84, 104, 99, 235}, account.Address.Bytes()) && key == "price_209553" { + return nil, errors.New("not found") + } + + panic(fmt.Sprintf("RetrieveNewestIntegerEntryFunc %+v %s", account.Address.Bytes(), key)) + //if !bytes.Equal(account.Address.Bytes(), this) { + // panic("unknown account " + account.String()) + //} + // + //switch key { + //case "coefficient_oracle": + // return &proto.IntegerDataEntry{Key: key, Value: 3}, nil + //case "price_209553": + // return &proto.IntegerDataEntry{Key: key, Value: 60}, nil + //default: + // panic("unknown key " + key) + //} + }, + RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { + //case "is_blocked": + return nil, errors.New(key + " not found") + }, + // 1053 + RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + if !bytes.Equal(account.Address.Bytes(), this) { + panic("not equal bytes") + } + switch key { + // 4 + case "oracles": + return &proto.StringDataEntry{Key: key, Value: "3MbAmZFN3uQ1j2SMj28K32esXKSre2uVVf8,3MRzeHJTxhcAw3FhPbwPSR2ZxA7M8hA5AzV,3MVxxrC79QE2tZufp3pdoWWpnNPpZw3Vw2A,3Mczj2UD9swFgFCyqpfPAacJpn2UTu43vVY,3MYzuVPkN2gaLa5RDUesuUQEq8wWh7Y71GR"}, nil + default: + panic("unknown key " + key) + } + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'S' + }, + checkMessageLengthFunc: func(in1 int) bool { + return true + }, + thisFunc: func() rideType { + return rideBytes(this) + }, + invocationFunc: func() rideObject { + return nil + }, + heightFunc: func() rideInt { + return rideInt(209553) + }, + } + + rsT, err := CallTreeFunction("", env, tree, "finalizeCurrentPrice", nil) + require.NoError(t, err) + _ = rsT + + rs, err := script.Invoke(env, "finalizeCurrentPrice", nil) + require.NoError(t, err) + //require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, true, rs.Result()) +} + +func TestExpandSmthWrote3(t *testing.T) { + source := `AwoBAAAAC0lzUGxheWVyV2luAAAAAgAAAAxwbGF5ZXJDaG9pY2UAAAAHcmFuZFN0cgQAAAABcwkAATEAAAABBQAAAAxwbGF5ZXJDaG9pY2UDAwMDAwkAAGcAAAACBQAAAAFzAAAAAAAAAAABCQAAAAAAAAIJAAEvAAAAAgkAATAAAAACBQAAAAxwbGF5ZXJDaG9pY2UAAAAAAAAAAAAAAAAAAAAAAAEFAAAAB3JhbmRTdHIHBgMJAABnAAAAAgUAAAABcwAAAAAAAAAAAgkAAAAAAAACCQABLwAAAAIJAAEwAAAAAgUAAAAMcGxheWVyQ2hvaWNlAAAAAAAAAAABAAAAAAAAAAABBQAAAAdyYW5kU3RyBwYDCQAAZwAAAAIFAAAAAXMAAAAAAAAAAAMJAAAAAAAAAgkAAS8AAAACCQABMAAAAAIFAAAADHBsYXllckNob2ljZQAAAAAAAAAAAgAAAAAAAAAAAQUAAAAHcmFuZFN0cgcGAwkAAGcAAAACBQAAAAFzAAAAAAAAAAAECQAAAAAAAAIJAAEvAAAAAgkAATAAAAACBQAAAAxwbGF5ZXJDaG9pY2UAAAAAAAAAAAMAAAAAAAAAAAEFAAAAB3JhbmRTdHIHBgMJAAAAAAAAAgUAAAABcwAAAAAAAAAABQkAAAAAAAACCQABLwAAAAIJAAEwAAAAAgUAAAAMcGxheWVyQ2hvaWNlAAAAAAAAAAAEAAAAAAAAAAABBQAAAAdyYW5kU3RyBwkBAAAAC0lzUGxheWVyV2luAAAAAgIAAAACYWECAAAAAmJinpP4rw==` + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + tree = MustExpand(tree) + t.Log(DecompileTree(tree)) + //require.NoError(t, err) + //require.NotNil(t, tree) + // + script, err := CompileTree("", tree) + require.NoError(t, err) + + //rsT, err := CallTreeVerifier(nil, tree) + //require.NoError(t, err) + //_ = rsT + // + //rs, err := script.Invoke(defaultEnv, "addBuyBondOrder", []rideType{rideInt(1398601), rideString("")}) + rs, err := script.Verify(defaultEnv) + require.NoError(t, err) + ////require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, true, rs.Result()) +} diff --git a/pkg/ride/vm.go b/pkg/ride/vm.go index 46b2dccb85..567f163f6b 100644 --- a/pkg/ride/vm.go +++ b/pkg/ride/vm.go @@ -192,6 +192,9 @@ func (m *vm) run() (rideType, error) { } m.push(rs) } else { + if m.ip == int(point.position)+3 { + return nil, errors.Errorf("infinity loop detected on iteration %d", m.numOperations) + } m.jmps = append(m.jmps, m.ip) m.ip = int(point.position) } diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 982ff25161..948ef9bae6 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -166,7 +166,11 @@ func (ss *scriptsStorage) setScript(scriptType blockchainEntity, key []byte, rec if err != nil { return err } - exe, err = ride.CompileTree("scriptsStorage setScript "+txID, p) + expandedTree, err := ride.Expand(p) + if err != nil { + return err + } + exe, err = ride.CompileTree("scriptsStorage setScript "+txID, expandedTree) if err != nil { return err } From 9c1b5004218bbb24613b41270654a1a373811b55 Mon Sep 17 00:00:00 2001 From: frozen Date: Tue, 16 Mar 2021 20:53:47 +0300 Subject: [PATCH 40/55] Rewrite tree by using immutable context with variables. --- go.sum | 13 -- pkg/ride/tree_evaluation.go | 67 ++++---- pkg/ride/tree_evaluation_test.go | 2 +- pkg/ride/tree_evaluator.go | 262 ++++++++++++++++++++----------- pkg/state/scripts_storage.go | 10 +- 5 files changed, 210 insertions(+), 144 deletions(-) diff --git a/go.sum b/go.sum index 718541bde3..52d506fdfa 100644 --- a/go.sum +++ b/go.sum @@ -14,7 +14,6 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= @@ -55,7 +54,6 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coocood/freecache v1.1.0 h1:ENiHOsWdj1BrrlPwblhbn4GdAsMymK3pZORJ+bJGAjA= @@ -76,21 +74,13 @@ github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbT github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 h1:Wm7GcUEhq0kioHEMLVVR9lyRezJsyzl9uLGnsQkijMU= github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942/go.mod h1:ZWP59etEywfyMG2lAqnoi3t8uoiZCiTmLtwt6iESIsQ= github.com/ethereum/go-ethereum v1.9.15/go.mod h1:slT8bPPRhXsyNTwHQxrOnjuTZ1sDXRajW11EkJ84QJ0= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b h1:pxBLQ5mIlm4mKl2lx1IhwLhpAu2XhnDDn2a+ooAN8dU= -github.com/frozen/immutable_map v0.0.0-20200831220546-14f58278114b/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= -github.com/frozen/immutable_map v0.0.0-20210224145525-b2feefc1f762 h1:5DnPrjV5ZRHl2jh+VVpnl0nR/in3AYP8j/6vWvKWzeE= -github.com/frozen/immutable_map v0.0.0-20210224145525-b2feefc1f762/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= -github.com/frozen/immutable_map v0.0.0-20210224161639-a72734704977 h1:ViTVPEPcu1DRvkN1WTIEiL6S7qXsgJGlKnZYpSnnSRo= -github.com/frozen/immutable_map v0.0.0-20210224161639-a72734704977/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4 h1:QJdN7XRRAp+ZEGl0ha5rjuL5/XJrEMtht0csVoVcvHA= github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= @@ -209,7 +199,6 @@ github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssy github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -265,7 +254,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -362,7 +350,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 8f30948be7..f63938900d 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -2,9 +2,7 @@ package ride import ( "github.com/pkg/errors" - "github.com/stretchr/testify/assert" "github.com/wavesplatform/gowaves/pkg/proto" - "go.uber.org/zap" ) func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { @@ -23,40 +21,40 @@ func CallVmVerifier(txID string, env RideEnvironment, compiled *Executable) (Rid } func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) (RideResult, error) { - r, err := CallVmVerifier(txID, env, exe) - if err != nil { - return nil, errors.Wrap(err, "vm verifier") - } - r2, err := CallTreeVerifier(env, tree) + //r, err := CallVmVerifier(txID, env, exe) + //if err != nil { + // return nil, errors.Wrap(err, "vm verifier") + //} + r2, err := CallTreeVerifier(env, MustExpand(tree)) if err != nil { return nil, errors.Wrap(err, "tree verifier") } + // + //if !r.Eq(r2) { + // c1 := r.Calls() + // c2 := r2.Calls() + // max := len(c1) + // if len(c2) > len(c1) { + // max = len(c2) + // } + // for i := 0; i < max; i++ { + // //zap.S().Error("R1 != R2: failed to call account script on transaction ") + // if i <= len(c1)-1 { + // zap.S().Error(i, txID, " ", c1[i]) + // } else { + // zap.S().Error(i, txID, " ", "") + // } + // if i <= len(c2)-1 { + // zap.S().Error(i, txID, " ", c2[i]) + // } else { + // zap.S().Error(i, txID, " ", "") + // } + // } + // + // return nil, errors.New("R1 != R2: failed to call account script on transaction ") + //} - if !r.Eq(r2) { - c1 := r.Calls() - c2 := r2.Calls() - max := len(c1) - if len(c2) > len(c1) { - max = len(c2) - } - for i := 0; i < max; i++ { - //zap.S().Error("R1 != R2: failed to call account script on transaction ") - if i <= len(c1)-1 { - zap.S().Error(i, txID, " ", c1[i]) - } else { - zap.S().Error(i, txID, " ", "") - } - if i <= len(c2)-1 { - zap.S().Error(i, txID, " ", c2[i]) - } else { - zap.S().Error(i, txID, " ", "") - } - } - - return nil, errors.New("R1 != R2: failed to call account script on transaction ") - } - - return r, nil + return r2, nil } func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { @@ -71,10 +69,12 @@ func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, } func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - rs1, err := CallTreeFunction(txID, env, tree, name, args) + rs1, err := CallTreeFunction(txID, env, MustExpand(tree), name, args) if err != nil { return nil, errors.Wrap(err, "call function by tree") } + return rs1, nil + /* * rs2, err := CallVmFunction(txID, env, exe, name, args) if err != nil { return rs2, errors.Wrap(err, "call function by vm") @@ -112,6 +112,7 @@ func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, return nil, errors.New("R1 != R2: failed to call account script on transaction ") } return rs2, nil + /* */ } func CallVmFunction(txID string, env RideEnvironment, e *Executable, name string, args proto.Arguments) (RideResult, error) { diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 8ff628051e..4fd405b8df 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -49,7 +49,7 @@ func TestSimpleScriptEvaluation(t *testing.T) { {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, {`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, {`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, - {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, + {`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", env, true}, {`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, {`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, {`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index 76b93aacb1..b8b1def21b 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -1,11 +1,71 @@ package ride import ( + im "github.com/frozen/immutable_map" "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/proto" ) -type evaluationCtx struct { +type varsCtx struct { + im *im.Map +} + +func (a varsCtx) add(name string, n Node, funcCtx funcCtx) varsCtx { + return varsCtx{ + im: a.im.Insert([]byte(name), &esValue{ + value: nil, + expression: n, + varsCtx: a, + funcCtx: funcCtx, + }), + } +} + +func (a varsCtx) addValue(name string, n rideType, funcCtx funcCtx) varsCtx { + return varsCtx{ + im: a.im.Insert([]byte(name), &esValue{ + value: n, + varsCtx: a, + funcCtx: funcCtx, + }), + } +} + +func (a varsCtx) get(name string) *esValue { + v := a.im.Get1([]byte(name)) + if v != nil { + return v.(*esValue) + } + return nil +} + +func newVarsCtx() varsCtx { + return varsCtx{im: im.New()} +} + +type funcCtx struct { + im *im.Map +} + +func (a funcCtx) add(name string, n *FunctionDeclarationNode, varsCtx varsCtx) funcCtx { + return funcCtx{ + im: a.im.Insert([]byte(name), &esFunction{ + fn: n, + varsCtx: varsCtx, + }), + } +} + +func (a funcCtx) get(name string) *esFunction { + v := a.im.Get1([]byte(name)) + if v == nil { + return nil + } + return v.(*esFunction) +} + +func newFuncCtx() funcCtx { + return funcCtx{im: im.New()} } type esConstant struct { @@ -17,51 +77,56 @@ type esValue struct { id string value rideType expression Node - size int + varsCtx varsCtx + funcCtx funcCtx } type esFunction struct { - fn *FunctionDeclarationNode - sp int + fn *FunctionDeclarationNode + varsCtx varsCtx } type evaluationScope struct { env RideEnvironment constants map[string]esConstant - cs [][]esValue + cs varsCtx + fs funcCtx system map[string]rideFunction - user []esFunction - cl int + //user []esFunction + cl int } func (s *evaluationScope) declare(n Node) error { switch d := n.(type) { case *FunctionDeclarationNode: - s.pushUserFunction(d) + //s.pushUserFunction(d) + s.fs = s.fs.add(d.Name, d, s.cs) return nil case *AssignmentNode: - s.pushExpression(d.Name, d.Expression) + //s.pushExpression(d.Name, d.Expression) + s.cs = s.cs.add(d.Name, d.Expression, s.fs) return nil default: return errors.Errorf("not a declaration '%T'", n) } } -func (s *evaluationScope) pushExpression(id string, n Node) { - s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, expression: n, size: len(s.cs[len(s.cs)-1])}) -} +//func (s *evaluationScope) pushExpression(id string, n Node) { +// s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, expression: n, size: len(s.cs[len(s.cs)-1])}) +//} //func (s *evaluationScope) pushExpression2(id string, n Node, ctx evaluationCtx) evaluationCtx { // //} func (s *evaluationScope) pushValue(id string, v rideType) { - s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, value: v}) + //s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, value: v}) + s.cs = s.cs.addValue(id, v, s.fs) } -func (s *evaluationScope) popValue() { - s.cs[len(s.cs)-1] = s.cs[len(s.cs)-1][:len(s.cs[len(s.cs)-1])-1] -} +//func (s *evaluationScope) popValue() { +// s.cs[len(s.cs)-1] = s.cs[len(s.cs)-1][:len(s.cs[len(s.cs)-1])-1] +//} func (s *evaluationScope) constant(id string) (rideType, bool) { if c, ok := s.constants[id]; ok { @@ -75,53 +140,53 @@ func (s *evaluationScope) constant(id string) (rideType, bool) { return nil, false } -func lookup(s []esValue, id string) (esValue, bool) { - for i := len(s) - 1; i >= 0; i-- { - if v := s[i]; v.id == id { - return v, true - } - } - return esValue{}, false -} +//func lookup(s []esValue, id string) (esValue, bool) { +// for i := len(s) - 1; i >= 0; i-- { +// if v := s[i]; v.id == id { +// return v, true +// } +// } +// return esValue{}, false +//} -func (s *evaluationScope) value(id string) (esValue, bool) { - if p := len(s.cs) - 1; p >= 0 { - v, ok := lookup(s.cs[p], id) - if ok { - return v, true - } - } - for i := s.cl - 1; i >= 0; i-- { - v, ok := lookup(s.cs[i], id) - if ok { - return v, true - } - } - return esValue{}, false -} +//func (s *evaluationScope) value(id string) (esValue, bool) { +//if p := len(s.cs) - 1; p >= 0 { +// v, ok := lookup(s.cs[p], id) +// if ok { +// return v, true +// } +//} +//for i := s.cl - 1; i >= 0; i-- { +// v, ok := lookup(s.cs[i], id) +// if ok { +// return v, true +// } +//} +//return esValue{}, false +//} -func (s *evaluationScope) pushUserFunction(uf *FunctionDeclarationNode) { - s.user = append(s.user, esFunction{fn: uf, sp: len(s.cs)}) -} +//func (s *evaluationScope) pushUserFunction(uf *FunctionDeclarationNode) { +// s.user = append(s.user, esFunction{fn: uf, sp: len(s.cs)}) +//} -func (s *evaluationScope) popUserFunction() error { - l := len(s.user) - if l == 0 { - return errors.New("empty user functions scope") - } - s.user = s.user[:l-1] - return nil -} +//func (s *evaluationScope) popUserFunction() error { +// l := len(s.user) +// if l == 0 { +// return errors.New("empty user functions scope") +// } +// s.user = s.user[:l-1] +// return nil +//} -func (s *evaluationScope) userFunction(id string) (*FunctionDeclarationNode, int, error) { - for i := len(s.user) - 1; i >= 0; i-- { - uf := s.user[i] - if uf.fn.Name == id { - return uf.fn, uf.sp, nil - } - } - return nil, 0, errors.Errorf("user function '%s' is not found", id) -} +//func (s *evaluationScope) userFunction(id string) (*FunctionDeclarationNode, int, error) { +// for i := len(s.user) - 1; i >= 0; i-- { +// uf := s.user[i] +// if uf.fn.Name == id { +// return uf.fn, uf.sp, nil +// } +// } +// return nil, 0, errors.Errorf("user function '%s' is not found", id) +//} func newEvaluationScope(v int, env RideEnvironment) (evaluationScope, error) { constants, err := selectConstantNames(v) @@ -167,8 +232,10 @@ func newEvaluationScope(v int, env RideEnvironment) (evaluationScope, error) { return evaluationScope{ constants: cs, system: fs, - cs: [][]esValue{make([]esValue, 0)}, - env: env, + //cs: //[][]esValue{make([]esValue, 0)}, + cs: newVarsCtx(), + fs: newFuncCtx(), + env: env, }, nil } @@ -223,7 +290,7 @@ type treeEvaluator struct { } func (e *treeEvaluator) evaluate() (RideResult, error) { - r, err := e.walk(e.f) + r, err := e.walk(e.f, e.s.cs, e.s.fs) if err != nil { return nil, err } @@ -260,7 +327,7 @@ func isThrow(r rideType) bool { return r.instanceOf() == "Throw" } -func (e *treeEvaluator) walk(node Node) (rideType, error) { +func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideType, error) { switch n := node.(type) { case *LongNode: return rideInt(n.Value), nil @@ -275,7 +342,7 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { return rideString(n.Value), nil case *ConditionalNode: - ce, err := e.walk(n.Condition) + ce, err := e.walk(n.Condition, varsCtx, funcCtx) if err != nil { return nil, errors.Wrap(err, "failed to estimate the condition of if") } @@ -287,28 +354,30 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { return nil, errors.Errorf("not a boolean") } if cr { - return e.walk(n.TrueExpression) + return e.walk(n.TrueExpression, varsCtx, funcCtx) } else { - return e.walk(n.FalseExpression) + return e.walk(n.FalseExpression, varsCtx, funcCtx) } case *AssignmentNode: id := n.Name - e.s.pushExpression(id, n.Expression) - r, err := e.walk(n.Block) + //e.s.pushExpression(id, n.Expression) + r, err := e.walk(n.Block, varsCtx.add(id, n.Expression, funcCtx), funcCtx) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate block after declaration of variable '%s'", id) } if isThrow(r) { return r, nil } - e.s.popValue() + //e.s.popValue() return r, nil case *ReferenceNode: id := n.Name - v, ok := e.s.value(id) - if !ok { + //v, ok := e.s.value(varsCtx, id) + v := varsCtx.get(id) + //ok := v != nil + if v == nil { if v, ok := e.s.constant(id); ok { return v, nil } @@ -318,32 +387,33 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { if v.expression == nil { return nil, errors.Errorf("scope value '%s' is empty", id) } - r, err := e.walk(v.expression) + r, err := e.walk(v.expression, v.varsCtx, v.funcCtx) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate expression of scope value '%s'", id) } if isThrow(r) { return r, nil } - e.s.pushValue(id, r) + //e.s.pushValue(id, r) + v.value = r return r, nil } return v.value, nil case *FunctionDeclarationNode: id := n.Name - e.s.pushUserFunction(n) - r, err := e.walk(n.Block) + //e.s.pushUserFunction(n) + r, err := e.walk(n.Block, varsCtx, funcCtx.add(id, n, varsCtx)) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate block after declaration of function '%s'", id) } if isThrow(r) { return r, nil } - err = e.s.popUserFunction() - if err != nil { - return nil, errors.Wrapf(err, "failed to evaluate declaration of function '%s'", id) - } + //err = e.s.popUserFunction() + //if err != nil { + // return nil, errors.Wrapf(err, "failed to evaluate declaration of function '%s'", id) + //} return r, nil case *FunctionCallNode: @@ -352,7 +422,7 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { if ok { // System function args := make([]rideType, len(n.Arguments)) for i, arg := range n.Arguments { - a, err := e.walk(arg) // materialize argument + a, err := e.walk(arg, varsCtx, funcCtx) // materialize argument if err != nil { return nil, errors.Wrapf(err, "failed to materialize argument %d of system function '%s'", i+1, id) } @@ -372,17 +442,19 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { } return r, nil } - uf, cl, err := e.s.userFunction(id) - if err != nil { - return nil, errors.Wrapf(err, "failed to call function '%s'", id) + //uf, _, err := e.s.userFunction(id) + uf := funcCtx.get(id) + if uf == nil { + return nil, errors.Errorf("failed to call function '%s'", id) } - if len(n.Arguments) != len(uf.Arguments) { + if len(n.Arguments) != len(uf.fn.Arguments) { return nil, errors.Errorf("mismatched arguments number of user function '%s'", id) } + localVars := uf.varsCtx args := make([]esValue, len(n.Arguments)) for i, arg := range n.Arguments { - an := uf.Arguments[i] - av, err := e.walk(arg) // materialize argument + an := uf.fn.Arguments[i] + av, err := e.walk(arg, varsCtx, funcCtx) // materialize argument if err != nil { return nil, errors.Wrapf(err, "failed to materialize argument '%s' of user function '%s", an, id) } @@ -390,25 +462,26 @@ func (e *treeEvaluator) walk(node Node) (rideType, error) { return av, nil } args[i] = esValue{id: an, value: av} + localVars = localVars.addValue(an, av, funcCtx) } //e.s.cs = append(e.s.cs, make([]esValue, len(args))) - e.s.cs = append(e.s.cs, args) + //e.s.cs = append(e.s.cs, args) //for i, arg := range args { // e.s.cs[len(e.s.cs)-1][i] = arg //} var tmp int - tmp, e.s.cl = e.s.cl, cl - r, err := e.walk(uf.Body) + //tmp, e.s.cl = e.s.cl, cl + r, err := e.walk(uf.fn.Body, localVars, funcCtx) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate function '%s' body", id) } - e.s.cs = e.s.cs[:len(e.s.cs)-1] + //e.s.cs = e.s.cs[:len(e.s.cs)-1] e.s.cl = tmp return r, nil case *PropertyNode: name := n.Name - obj, err := e.walk(n.Object) + obj, err := e.walk(n.Object, varsCtx, funcCtx) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate an object to get property '%s' on it", name) } @@ -493,7 +566,12 @@ func treeFunctionEvaluator(env RideEnvironment, tree *Tree, name string, args pr } s.pushValue(function.Arguments[i], a) } - return &treeEvaluator{dapp: true, f: function.Body, s: s, env: env}, nil + return &treeEvaluator{ + dapp: true, + f: function.Body, + s: s, + env: env, + }, nil } } return nil, errors.Errorf("function '%s' not found", name) diff --git a/pkg/state/scripts_storage.go b/pkg/state/scripts_storage.go index 948ef9bae6..0672ad0165 100644 --- a/pkg/state/scripts_storage.go +++ b/pkg/state/scripts_storage.go @@ -166,11 +166,11 @@ func (ss *scriptsStorage) setScript(scriptType blockchainEntity, key []byte, rec if err != nil { return err } - expandedTree, err := ride.Expand(p) - if err != nil { - return err - } - exe, err = ride.CompileTree("scriptsStorage setScript "+txID, expandedTree) + //expandedTree, err := ride.Expand(p) + //if err != nil { + // return err + //} + exe, err = ride.CompileTree("scriptsStorage setScript "+txID, p) if err != nil { return err } From 74b8cf321352aae50ed650383c5a21a46a25f2ef Mon Sep 17 00:00:00 2001 From: frozen Date: Wed, 17 Mar 2021 15:52:12 +0300 Subject: [PATCH 41/55] Fix problems with tree expand. --- go.mod | 2 +- go.sum | 2 ++ pkg/ride/tree_expand_test.go | 27 --------------------------- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index ae611d9daa..3786ac545d 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 - github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4 + github.com/frozen/immutable_map v0.1.0 github.com/fxamacker/cbor/v2 v2.2.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 diff --git a/go.sum b/go.sum index 52d506fdfa..bc0714993d 100644 --- a/go.sum +++ b/go.sum @@ -83,6 +83,8 @@ 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.0.0-20210226113144-8441e20b6fa4 h1:QJdN7XRRAp+ZEGl0ha5rjuL5/XJrEMtht0csVoVcvHA= github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= +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= diff --git a/pkg/ride/tree_expand_test.go b/pkg/ride/tree_expand_test.go index db24bcfa9c..0117b4bf26 100644 --- a/pkg/ride/tree_expand_test.go +++ b/pkg/ride/tree_expand_test.go @@ -11,7 +11,6 @@ import ( "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/proto" - //"github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/types" ) @@ -331,29 +330,3 @@ func TestExpandSmthWrote(t *testing.T) { //require.Equal(t, 2, len(rs.Calls())) require.Equal(t, true, rs.Result()) } - -func TestExpandSmthWrote3(t *testing.T) { - source := `AwoBAAAAC0lzUGxheWVyV2luAAAAAgAAAAxwbGF5ZXJDaG9pY2UAAAAHcmFuZFN0cgQAAAABcwkAATEAAAABBQAAAAxwbGF5ZXJDaG9pY2UDAwMDAwkAAGcAAAACBQAAAAFzAAAAAAAAAAABCQAAAAAAAAIJAAEvAAAAAgkAATAAAAACBQAAAAxwbGF5ZXJDaG9pY2UAAAAAAAAAAAAAAAAAAAAAAAEFAAAAB3JhbmRTdHIHBgMJAABnAAAAAgUAAAABcwAAAAAAAAAAAgkAAAAAAAACCQABLwAAAAIJAAEwAAAAAgUAAAAMcGxheWVyQ2hvaWNlAAAAAAAAAAABAAAAAAAAAAABBQAAAAdyYW5kU3RyBwYDCQAAZwAAAAIFAAAAAXMAAAAAAAAAAAMJAAAAAAAAAgkAAS8AAAACCQABMAAAAAIFAAAADHBsYXllckNob2ljZQAAAAAAAAAAAgAAAAAAAAAAAQUAAAAHcmFuZFN0cgcGAwkAAGcAAAACBQAAAAFzAAAAAAAAAAAECQAAAAAAAAIJAAEvAAAAAgkAATAAAAACBQAAAAxwbGF5ZXJDaG9pY2UAAAAAAAAAAAMAAAAAAAAAAAEFAAAAB3JhbmRTdHIHBgMJAAAAAAAAAgUAAAABcwAAAAAAAAAABQkAAAAAAAACCQABLwAAAAIJAAEwAAAAAgUAAAAMcGxheWVyQ2hvaWNlAAAAAAAAAAAEAAAAAAAAAAABBQAAAAdyYW5kU3RyBwkBAAAAC0lzUGxheWVyV2luAAAAAgIAAAACYWECAAAAAmJinpP4rw==` - - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - tree = MustExpand(tree) - t.Log(DecompileTree(tree)) - //require.NoError(t, err) - //require.NotNil(t, tree) - // - script, err := CompileTree("", tree) - require.NoError(t, err) - - //rsT, err := CallTreeVerifier(nil, tree) - //require.NoError(t, err) - //_ = rsT - // - //rs, err := script.Invoke(defaultEnv, "addBuyBondOrder", []rideType{rideInt(1398601), rideString("")}) - rs, err := script.Verify(defaultEnv) - require.NoError(t, err) - ////require.Equal(t, 2, len(rs.Calls())) - require.Equal(t, true, rs.Result()) -} From be99ac984ec6424ebbe598d01e86310cbab7a4c0 Mon Sep 17 00:00:00 2001 From: frozen Date: Thu, 18 Mar 2021 17:28:24 +0300 Subject: [PATCH 42/55] Fix naming. --- pkg/ride/compiler.go | 770 +++--------------- pkg/ride/compiler2.go | 144 ---- pkg/ride/compiler_assigment.go | 36 +- pkg/ride/compiler_call_system.go | 36 +- pkg/ride/compiler_call_user.go | 37 +- pkg/ride/compiler_conditional.go | 34 +- pkg/ride/compiler_func.go | 34 +- pkg/ride/compiler_main.go | 30 +- pkg/ride/compiler_property.go | 32 +- pkg/ride/compiler_state.go | 32 +- .../{compiler2_test.go => compiler_test.go} | 0 pkg/ride/deserializer.go | 12 +- pkg/ride/serializer.go | 20 +- pkg/ride/tree_estimatorV3.go | 1 + pkg/ride/tree_expand.go | 1 - pkg/ride/tree_expand_test.go | 19 +- pkg/ride/vm_test.go | 310 ------- 17 files changed, 255 insertions(+), 1293 deletions(-) delete mode 100644 pkg/ride/compiler2.go rename pkg/ride/{compiler2_test.go => compiler_test.go} (100%) diff --git a/pkg/ride/compiler.go b/pkg/ride/compiler.go index 7654bb75b7..08b74df28f 100644 --- a/pkg/ride/compiler.go +++ b/pkg/ride/compiler.go @@ -1,720 +1,154 @@ package ride -//go:generate go run ./generate - import ( - "bytes" - "encoding/binary" "math" "github.com/pkg/errors" + "go.uber.org/zap" ) -func Compile(tree *Tree) (RideScript, error) { - fCheck, err := selectFunctionChecker(tree.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "compile") - } - cCheck, err := selectConstantsChecker(tree.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "compile") - } - c := &compiler{ - constants: newRideConstants(), - checkFunction: fCheck, - checkConstant: cCheck, - values: make([]rideValue, 0), - functions: make([]*localFunction, 0), - declarations: make([]rideDeclaration, 0), - patcher: newPatcher(), - } - if tree.IsDApp() { - return c.compileDAppScript(tree) - } - return c.compileSimpleScript(tree) -} - -type compiler struct { - constants *rideConstants - checkFunction func(string) (uint16, bool) - checkConstant func(string) (uint16, bool) - values []rideValue - functions []*localFunction - declarations []rideDeclaration - patcher *patcher - callable *rideCallable -} +import ( + "encoding/binary" +) -func (c *compiler) compileSimpleScript(tree *Tree) (*SimpleScript, error) { - bb := new(bytes.Buffer) - err := c.compile(bb, tree.Verifier) - if err != nil { - return nil, err - } - bb.WriteByte(OpHalt) - for _, d := range c.declarations { - pos := bb.Len() - c.patcher.setOrigin(d.buffer(), pos) - bb.Write(patchedCode(d.buffer(), pos)) - bb.WriteByte(OpReturn) - for _, ref := range d.references() { - c.patcher.setPosition(ref, uint16(pos)) - } - } - code := bb.Bytes() - patches, err := c.patcher.get() - if err != nil { - return nil, err - } - for pos, addr := range patches { - binary.BigEndian.PutUint16(code[pos:], addr) - } - return &SimpleScript{ - LibVersion: tree.LibVersion, - EntryPoint: 0, - Code: bb.Bytes(), - Constants: c.constants.items, - }, nil +func encode(v uint16) []byte { + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, v) + return b } -func (c *compiler) compileDAppScript(tree *Tree) (*DAppScript, error) { - // Compile global declarations. - // Each declaration goes to the declaration stack with code compiled in its own buffer. - functions := make(map[string]callable) - bb := new(bytes.Buffer) - for _, node := range tree.Declarations { - err := c.compile(bb, node) - if err != nil { - return nil, err - } - } - for _, n := range tree.Functions { - fn, ok := n.(*FunctionDeclarationNode) - if !ok { - return nil, errors.Errorf("invalid node type %T", n) - } - c.callable = &rideCallable{ - name: fn.Name, - parameter: fn.invocationParameter, - } - err := c.compile(bb, fn) - if err != nil { - return nil, err - } - } - if tree.HasVerifier() { - v, ok := tree.Verifier.(*FunctionDeclarationNode) - if !ok { - return nil, errors.Errorf("invalid node type for DApp's verifier '%T'", tree.Verifier) - } - c.callable = &rideCallable{ - name: "", // Verifier has empty name - parameter: v.invocationParameter, - } - err := c.compile(bb, v) +func compile(f State, node Node) (State, error) { + switch n := node.(type) { + case *AssignmentNode: + fsm, err := compile(f.Assigment(n.Name), n.Expression) if err != nil { - return nil, err + return fsm, err } - functions[""] = callable{ - entryPoint: 0, - parameterName: v.invocationParameter, - } - } - // All declarations goes here after verifier and public functions - for _, d := range c.declarations { - pos := bb.Len() - c.patcher.setOrigin(d.buffer(), pos) - bb.Write(patchedCode(d.buffer(), pos)) - if c := d.callable(); c != nil { - bb.WriteByte(OpHalt) - // Add reference to entry point - functions[c.name] = callable{ - entryPoint: pos, - parameterName: c.parameter, + return compile(fsm.Return(), n.Block) + case *LongNode: + return f.Long(n.Value), nil + case *FunctionCallNode: + var err error + f = f.Call(n.Name, uint16(len(n.Arguments))) + for i := range n.Arguments { + f, err = compile(f, n.Arguments[i]) + if err != nil { + return f, err } - } else { - bb.WriteByte(OpReturn) } - for _, ref := range d.references() { - c.patcher.setPosition(ref, uint16(pos)) - } - } - code := bb.Bytes() - patches, err := c.patcher.get() - if err != nil { - return nil, err - } - for pos, addr := range patches { - binary.BigEndian.PutUint16(code[pos:], addr) - } - return &DAppScript{ - LibVersion: tree.LibVersion, - Code: bb.Bytes(), - Constants: c.constants.items, - EntryPoints: functions, - }, nil -} - -func (c *compiler) compile(bb *bytes.Buffer, node Node) error { - switch n := node.(type) { - case *LongNode: - return c.longNode(bb, n) - case *BytesNode: - return c.bytesNode(bb, n) - case *StringNode: - return c.stringNode(bb, n) + return f.Return(), nil + case *ReferenceNode: + return f.Reference(n.Name), nil case *BooleanNode: - return c.booleanNode(bb, n) + return f.Boolean(n.Value), nil + case *StringNode: + return f.String(n.Value), nil + case *BytesNode: + return f.Bytes(n.Value), nil case *ConditionalNode: - return c.conditionalNode(bb, n) - case *AssignmentNode: - return c.assignmentNode(bb, n) - case *ReferenceNode: - return c.referenceNode(bb, n) - case *FunctionDeclarationNode: - return c.functionDeclarationNode(bb, n) - case *FunctionCallNode: - return c.callNode(bb, n) - case *PropertyNode: - return c.propertyNode(bb, n) - default: - return errors.Errorf("unexpected node type '%T'", node) - } -} - -func (c *compiler) longNode(bb *bytes.Buffer, node *LongNode) error { - cid, err := c.constants.put(rideInt(node.Value)) - if err != nil { - return err - } - bb.WriteByte(OpPush) - bb.Write(encode(cid)) - return nil -} - -func (c *compiler) bytesNode(bb *bytes.Buffer, node *BytesNode) error { - cid, err := c.constants.put(rideBytes(node.Value)) - if err != nil { - return err - } - bb.WriteByte(OpPush) - bb.Write(encode(cid)) - return nil -} - -func (c *compiler) stringNode(bb *bytes.Buffer, node *StringNode) error { - cid, err := c.constants.put(rideString(node.Value)) - if err != nil { - return err - } - bb.WriteByte(OpPush) - bb.Write(encode(cid)) - return nil -} - -func (c *compiler) booleanNode(bb *bytes.Buffer, node *BooleanNode) error { - if node.Value { - bb.WriteByte(OpTrue) - } else { - bb.WriteByte(OpFalse) - } - return nil -} - -func (c *compiler) conditionalNode(bb *bytes.Buffer, node *ConditionalNode) error { - err := c.compile(bb, node.Condition) - if err != nil { - return err - } - bb.WriteByte(OpJumpIfFalse) - otherwise := bb.Len() - bb.Write([]byte{0xff, 0xff}) - - // Truthy branch - bb.WriteByte(OpPop) // Remove condition result from stack - - err = c.compile(bb, node.TrueExpression) - if err != nil { - return err - } - - bb.WriteByte(OpJump) - end := bb.Len() - bb.Write([]byte{0xff, 0xff}) - - // Patch ref to alternative branch - code := bb.Bytes() - binary.BigEndian.PutUint16(code[otherwise:], uint16(bb.Len())) - - // Alternative branch - bb.WriteByte(OpPop) // Remove condition result from stack - err = c.compile(bb, node.FalseExpression) - if err != nil { - return err - } - - // Patch ref to the end of alternative branch - code = bb.Bytes() - binary.BigEndian.PutUint16(code[end:], uint16(bb.Len())) - - return nil -} - -func (c *compiler) assignmentNode(bb *bytes.Buffer, node *AssignmentNode) error { - err := c.pushGlobalValue(node.Name, node.Expression, c.callable) - if err != nil { - return err - } - if node.Block != nil { - err = c.compile(bb, node.Block) - if err != nil { - return err - } - err = c.popValue() + f, err := compile(f.Condition(), n.Condition) if err != nil { - return err + return f, err } - } else { - err = c.peekValue() + f, err = compile(f.TrueBranch(), n.TrueExpression) if err != nil { - return err + return f, err } - } - return nil -} - -func (c *compiler) referenceNode(bb *bytes.Buffer, node *ReferenceNode) error { - if id, ok := c.checkConstant(node.Name); ok { - //Globally declared constant - bb.WriteByte(OpGlobal) - bb.Write(encode(id)) - return nil - } else { - v, err := c.lookupValue(node.Name) + f, err = compile(f.FalseBranch(), n.FalseExpression) if err != nil { - return err - } - switch value := v.(type) { - case *localValue: - bb.WriteByte(OpLoadLocal) - bb.Write(encode(value.position)) - return nil - case *globalValue: - bb.WriteByte(OpLoad) - value.refer(c.patcher.add(bb)) - bb.Write([]byte{0xff, 0xff}) - return nil - default: - return errors.Errorf("unexpected value type '%T'", value) + return f, err } - } -} - -func (c *compiler) functionDeclarationNode(bb *bytes.Buffer, node *FunctionDeclarationNode) error { - var args []string - if c.callable != nil { // DApp callable function - args = make([]string, len(node.Arguments)+1) - args[0] = c.callable.parameter - copy(args[1:], node.Arguments) - } else { - args = node.Arguments - } - err := c.pushFunction(node.Name, args, node.Body, c.callable) - if err != nil { - return err - } - if node.Block != nil { - err = c.compile(bb, node.Block) - if err != nil { - return err - } - err = c.popFunction() - if err != nil { - return err - } - } else { - err = c.peekFunction() - if err != nil { - return err - } - } - return nil -} - -func (c *compiler) callNode(bb *bytes.Buffer, node *FunctionCallNode) error { - for _, arg := range node.Arguments { - err := c.compile(bb, arg) + return f.Return(), nil + case *FunctionDeclarationNode: + fsm, err := compile(f.Func(n.Name, n.Arguments, n.invocationParameter), n.Body) if err != nil { - return err + return fsm, err } - } - cnt := encode(uint16(len(node.Arguments))) - - if id, ok := c.checkFunction(node.Name); ok { - //External function - bb.WriteByte(OpExternalCall) - bb.Write(encode(id)) - bb.Write(cnt) - } else { - //Internal function - decl, err := c.lookupFunction(node.Name) + return compile(fsm.Return(), n.Block) + case *PropertyNode: + f, err := compile(f.Property(n.Name), n.Object) if err != nil { - return err + return f, err } - bb.WriteByte(OpCall) - decl.call(c.patcher.add(bb)) - bb.Write([]byte{0xff, 0xff}) - bb.Write(cnt) - } - return nil -} - -func (c *compiler) propertyNode(bb *bytes.Buffer, node *PropertyNode) error { - err := c.compile(bb, node.Object) - if err != nil { - return err - } - id, err := c.constants.put(rideString(node.Name)) - if err != nil { - return err - } - bb.WriteByte(OpProperty) - bb.Write(encode(id)) - return nil -} - -func (c *compiler) pushGlobalValue(name string, node Node, annex *rideCallable) error { - d := newGlobalValue(name, annex) - c.callable = nil - c.values = append(c.values, d) - err := c.compile(d.bb, node) - if err != nil { - return err - } - return nil -} - -func (c *compiler) popValue() error { - l := len(c.values) - if l == 0 { - return errors.New("failed to pop value from empty stack") - } - var v rideValue - v, c.values = c.values[l-1], c.values[:l-1] - if d, ok := v.(rideDeclaration); ok { - c.declarations = append(c.declarations, d) - } - return nil -} - -func (c *compiler) peekValue() error { - l := len(c.values) - if l == 0 { - return errors.New("failed to peek value from empty stack") - } - v := c.values[l-1] - if d, ok := v.(rideDeclaration); ok { - c.declarations = append(c.declarations, d) + return f.Return(), nil + case nil: + // it should be dapp + return f, nil + default: + return f, errors.Errorf("unknown type %T", node) } - return nil } -func (c *compiler) lookupValue(name string) (rideValue, error) { - for i := len(c.values) - 1; i >= 0; i-- { - if c.values[i].id() == name { - return c.values[i], nil +func CompileVerifier(txID string, tree *Tree) (*Executable, error) { + if tree.IsDApp() { + if tree.HasVerifier() { + _, ok := tree.Verifier.(*FunctionDeclarationNode) + if !ok { + return nil, errors.New("invalid verifier declaration") + } + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier), tree.IsDApp(), tree.HasVerifier()) } + return nil, errors.New("no verifier declaration") } - return nil, errors.Errorf("value '%s' is not declared", name) + return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, tree.IsDApp(), tree.HasVerifier()) } -func (c *compiler) pushFunction(name string, args []string, node Node, annex *rideCallable) error { - d := newLocalFunction(name, args, annex) - c.functions = append(c.functions, d) - for i, a := range args { - c.values = append(c.values, newLocalValue(a, i)) - } - c.callable = nil - err := c.compile(d.bb, node) - if err != nil { - return err - } - for range args { - err := c.popValue() - if err != nil { - return err +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") } + }() + if !tree.IsDApp() { + return nil, errors.Errorf("unable to compile dappp") } - return nil -} - -func (c *compiler) popFunction() error { - l := len(c.functions) - if l == 0 { - return errors.New("failed to pop function from empty stack") + fns := tree.Functions + if tree.HasVerifier() { + fns = append(fns, tree.Verifier) } - var f *localFunction - f, c.functions = c.functions[l-1], c.functions[:l-1] - c.declarations = append(c.declarations, f) - return nil + return compileFunction(txID, tree.LibVersion, append(tree.Declarations, fns...), true, tree.HasVerifier()) } -func (c *compiler) peekFunction() error { - l := len(c.functions) - if l == 0 { - return errors.New("failed to peek function from empty stack") +func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool, hasVerifier bool) (*Executable, error) { + fCheck, err := selectFunctionChecker(libVersion) + if err != nil { + return nil, err } - f := c.functions[l-1] - c.declarations = append(c.declarations, f) - return nil -} + u := &uniqid{} + b := newBuilder() + r := newReferences(nil) + c := newCell() + b.writeByte(OpReturn) -func (c *compiler) lookupFunction(name string) (*localFunction, error) { - for i := len(c.functions) - 1; i >= 0; i-- { - if c.functions[i].name == name { - return c.functions[i], nil - } + params := params{ + b: b, + r: r, + f: fCheck, + u: u, + c: c, + txID: txID, } - return nil, errors.Errorf("function '%s' is not declared", name) -} - -type rideCallable struct { - name string - parameter string -} - -type rideConstants struct { - items []rideType - strings map[string]uint16 -} - -func newRideConstants() *rideConstants { - return &rideConstants{ - items: make([]rideType, 0, 4), - strings: make(map[string]uint16, 4), + for k, v := range predefinedFunctions { + params.addPredefined(v.name, uint16(math.MaxUint16-k), uint16(math.MaxUint16-k)) } -} -func (c *rideConstants) put(value rideType) (uint16, error) { - switch v := value.(type) { - case rideString: - s := string(v) - if pos, ok := c.strings[s]; ok { - return pos, nil - } - pos, err := c.append(value) - if err != nil { - return 0, err - } - c.strings[s] = pos - return pos, nil - default: - pos, err := c.append(value) + f := NewMain(params) + for _, node := range nodes { + f, err = compile(f, node) if err != nil { - return 0, err - } - return pos, nil - } -} - -func (c *rideConstants) append(value rideType) (uint16, error) { - if len(c.items) >= math.MaxUint16 { - return 0, errors.New("max number of constants reached") - } - c.items = append(c.items, value) - return uint16(len(c.items) - 1), nil -} - -type rideDeclaration interface { - buffer() *bytes.Buffer - references() []int - callable() *rideCallable -} - -type rideValue interface { - id() string -} - -type localValue struct { - name string - position uint16 -} - -func newLocalValue(name string, pos int) *localValue { - return &localValue{ - name: name, - position: uint16(pos), - } -} - -func (v *localValue) id() string { - return v.name -} - -type globalValue struct { - name string - annex *rideCallable - bb *bytes.Buffer - usages []int - using []*globalValue -} - -func newGlobalValue(name string, annex *rideCallable) *globalValue { - return &globalValue{ - name: name, - annex: annex, - bb: new(bytes.Buffer), - usages: make([]int, 0), - using: make([]*globalValue, 0), - } -} - -func (v *globalValue) buffer() *bytes.Buffer { - return v.bb -} - -func (v *globalValue) references() []int { - return v.usages -} - -func (v *globalValue) id() string { - return v.name -} - -func (v *globalValue) refer(patch int) { - v.usages = append(v.usages, patch) -} - -func (v *globalValue) callable() *rideCallable { - return v.annex -} - -type localFunction struct { - name string - annex *rideCallable - bb *bytes.Buffer - calls []int - args []string -} - -func newLocalFunction(name string, args []string, annex *rideCallable) *localFunction { - return &localFunction{ - name: name, - annex: annex, - bb: new(bytes.Buffer), - calls: make([]int, 0), - args: args, - } -} - -func (f *localFunction) buffer() *bytes.Buffer { - return f.bb -} - -func (f *localFunction) references() []int { - return f.calls -} - -func (f *localFunction) call(pos int) { - f.calls = append(f.calls, pos) -} - -func (f *localFunction) callable() *rideCallable { - return f.annex -} - -type patch struct { - id int - origin int - pos int - addr uint16 -} - -type patcher struct { - count int - buffers map[*bytes.Buffer][]patch -} - -func newPatcher() *patcher { - return &patcher{ - count: 0, - buffers: make(map[*bytes.Buffer][]patch), - } -} - -func (p *patcher) add(bb *bytes.Buffer) int { - pt := patch{ - id: p.count, - pos: bb.Len(), - } - if bps, ok := p.buffers[bb]; ok { - p.buffers[bb] = append(bps, pt) - } else { - p.buffers[bb] = []patch{pt} - } - p.count++ - return pt.id -} - -func (p *patcher) setOrigin(bb *bytes.Buffer, origin int) { - if ps, ok := p.buffers[bb]; ok { - for i := range ps { - ps[i].origin = origin - } - } -} - -func (p *patcher) setPosition(id int, addr uint16) { - for _, v := range p.buffers { - for i := range v { - if v[i].id == id { - v[i].addr = addr - } + return nil, err } } -} + // Just to write `OpReturn` to bytecode. + f = f.Return() -func (p *patcher) get() (map[int]uint16, error) { - r := make(map[int]uint16) - for _, v := range p.buffers { - for i := range v { - abs := v[i].origin + v[i].pos - if _, ok := r[abs]; ok { - return nil, errors.Errorf("duplicate patch at position %d", abs) - } - r[abs] = v[i].addr - } - } - return r, nil + return f.(BuildExecutable).BuildExecutable(libVersion, isDapp, hasVerifier), nil } -func encode(v uint16) []byte { - b := make([]byte, 2) - binary.BigEndian.PutUint16(b, v) - return b -} - -func patchedCode(bb *bytes.Buffer, origin int) []byte { - bts := bb.Bytes() - i := 0 - for i < bb.Len() { - switch bts[i] { - case OpJumpIfFalse, OpJump: - addr := bts[i+1 : i+3] - update(addr, origin) - i += 3 - case OpPush, OpProperty, OpLoad, OpLoadLocal, OpGlobal: - i += 3 - case OpCall, OpExternalCall: - i += 5 - default: - i++ - } +func CompileTree(tx string, tree *Tree) (*Executable, error) { + if tree.IsDApp() { + return CompileDapp(tx, tree) } - return bts -} - -func update(b []byte, n int) { - v := binary.BigEndian.Uint16(b) - binary.BigEndian.PutUint16(b, uint16(int(v)+n)) + return CompileVerifier(tx, tree) } diff --git a/pkg/ride/compiler2.go b/pkg/ride/compiler2.go deleted file mode 100644 index 4808996fab..0000000000 --- a/pkg/ride/compiler2.go +++ /dev/null @@ -1,144 +0,0 @@ -package ride - -import ( - "math" - - "github.com/pkg/errors" - "go.uber.org/zap" -) - -func ccc(f Fsm, node Node) (Fsm, error) { - switch n := node.(type) { - case *AssignmentNode: - fsm, err := ccc(f.Assigment(n.Name), n.Expression) - if err != nil { - return fsm, err - } - return ccc(fsm.Return(), n.Block) - case *LongNode: - return f.Long(n.Value), nil - case *FunctionCallNode: - var err error - f = f.Call(n.Name, uint16(len(n.Arguments))) - for i := range n.Arguments { - f, err = ccc(f, n.Arguments[i]) - if err != nil { - return f, err - } - } - return f.Return(), nil - case *ReferenceNode: - return f.Reference(n.Name), nil - case *BooleanNode: - return f.Boolean(n.Value), nil - case *StringNode: - return f.String(n.Value), nil - case *BytesNode: - return f.Bytes(n.Value), nil - case *ConditionalNode: - f, err := ccc(f.Condition(), n.Condition) - if err != nil { - return f, err - } - f, err = ccc(f.TrueBranch(), n.TrueExpression) - if err != nil { - return f, err - } - f, err = ccc(f.FalseBranch(), n.FalseExpression) - if err != nil { - return f, err - } - return f.Return(), nil - case *FunctionDeclarationNode: - fsm, err := ccc(f.Func(n.Name, n.Arguments, n.invocationParameter), n.Body) - if err != nil { - return fsm, err - } - return ccc(fsm.Return(), n.Block) - case *PropertyNode: - f, err := ccc(f.Property(n.Name), n.Object) - if err != nil { - return f, err - } - return f.Return(), nil - case nil: - // it should be dapp - return f, nil - default: - return f, errors.Errorf("unknown type %T", node) - } -} - -func CompileVerifier(txID string, tree *Tree) (*Executable, error) { - if tree.IsDApp() { - if tree.HasVerifier() { - _, ok := tree.Verifier.(*FunctionDeclarationNode) - if !ok { - return nil, errors.New("invalid verifier declaration") - } - return compileFunction(txID, tree.LibVersion, append(tree.Declarations, tree.Verifier), tree.IsDApp(), tree.HasVerifier()) - } - return nil, errors.New("no verifier declaration") - } - return compileFunction(txID, tree.LibVersion, []Node{tree.Verifier}, tree.IsDApp(), tree.HasVerifier()) -} - -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") - } - }() - if !tree.IsDApp() { - return nil, errors.Errorf("unable to compile dappp") - } - fns := tree.Functions - if tree.HasVerifier() { - fns = append(fns, tree.Verifier) - } - return compileFunction(txID, tree.LibVersion, append(tree.Declarations, fns...), true, tree.HasVerifier()) -} - -func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool, hasVerifier bool) (*Executable, error) { - fCheck, err := selectFunctionChecker(libVersion) - if err != nil { - return nil, err - } - u := &uniqid{} - b := newBuilder() - r := newReferences(nil) - c := newCell() - b.writeByte(OpReturn) - - params := params{ - b: b, - r: r, - f: fCheck, - u: u, - c: c, - txID: txID, - } - for k, v := range predefinedFunctions { - params.addPredefined(v.name, uint16(math.MaxUint16-k), uint16(math.MaxUint16-k)) - } - - f := NewMain(params) - for _, node := range nodes { - f, err = ccc(f, node) - if err != nil { - return nil, err - } - } - // Just to write `OpReturn` to bytecode. - f = f.Return() - - return f.(BuildExecutable).BuildExecutable(libVersion, isDapp, hasVerifier), nil -} - -func CompileTree(tx string, tree *Tree) (*Executable, error) { - if tree.IsDApp() { - return CompileDapp(tx, tree) - } - return CompileVerifier(tx, tree) -} diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 4d05bec1c5..6365c0b39d 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -6,7 +6,7 @@ import "fmt" type AssigmentState struct { params bodyParams params - prev Fsm + prev State name string // ref id n uniqueid @@ -16,47 +16,47 @@ type AssigmentState struct { d Deferreds } -func (a AssigmentState) backward(state Fsm) Fsm { +func (a AssigmentState) backward(state State) State { a.body = state.(Deferred) return a } -func (a AssigmentState) Property(name string) Fsm { +func (a AssigmentState) Property(name string) State { return propertyTransition(a, a.bodyParams, name, a.d) } -func (a AssigmentState) Func(name string, args []string, invoke string) Fsm { +func (a AssigmentState) Func(name string, args []string, invoke string) State { return funcTransition(a, a.bodyParams, name, args, invoke) } -func (a AssigmentState) Bytes(b []byte) Fsm { +func (a AssigmentState) Bytes(b []byte) State { a.body = a.constant(rideBytes(b)) return a } -func (a AssigmentState) Condition() Fsm { +func (a AssigmentState) Condition() State { return conditionalTransition(a, a.bodyParams, a.d) } -func (a AssigmentState) TrueBranch() Fsm { +func (a AssigmentState) TrueBranch() State { panic("Illegal call `TrueBranch` on AssigmentState") } -func (a AssigmentState) FalseBranch() Fsm { +func (a AssigmentState) FalseBranch() State { panic("Illegal call `FalseBranch` on AssigmentState") } -func (a AssigmentState) String(s string) Fsm { +func (a AssigmentState) String(s string) State { a.body = a.constant(rideString(s)) return a } -func (a AssigmentState) Boolean(v bool) Fsm { +func (a AssigmentState) Boolean(v bool) State { a.body = a.constant(rideBoolean(v)) return a } -func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid, d Deferreds) Fsm { +func assigmentFsmTransition(prev State, params params, name string, n uniqueid, d Deferreds) State { return newAssigmentFsm(prev, params, name, n, d) } @@ -65,7 +65,7 @@ func extendParams(p params) params { return p } -func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid, d Deferreds) Fsm { +func newAssigmentFsm(prev State, p params, name string, n uniqueid, d Deferreds) State { return AssigmentState{ prev: prev, params: p, @@ -77,7 +77,7 @@ func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid, d Deferreds) F } // Create new scope, so assigment in assigment can't affect global state. -func (a AssigmentState) Assigment(name string) Fsm { +func (a AssigmentState) Assigment(name string) State { //params := a.params //params.r = newReferences(params.r) // TODO clear var in var @@ -85,27 +85,27 @@ func (a AssigmentState) Assigment(name string) Fsm { return assigmentFsmTransition(a, a.bodyParams, name, n, a.d) } -func (a AssigmentState) Return() Fsm { +func (a AssigmentState) Return() State { a.r.setAssigment(a.name, a.n) a.d.Add(a, a.n, fmt.Sprintf("ref %s", a.name)) return a.prev } -func (a AssigmentState) Long(value int64) Fsm { +func (a AssigmentState) Long(value int64) State { a.body = a.constant(rideInt(value)) return a } -func (a AssigmentState) Call(name string, argc uint16) Fsm { +func (a AssigmentState) Call(name string, argc uint16) State { return callTransition(a, a.bodyParams, name, argc, a.d) } -func (a AssigmentState) Reference(name string) Fsm { +func (a AssigmentState) Reference(name string) State { a.body = reference(a, a.bodyParams, name) return a } -func (a AssigmentState) Write(_ params, b []byte) { +func (a AssigmentState) Write(_ params, _ []byte) { if a.body == nil { panic("no body for assigment") } diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index fc74077c0e..e22816b3e0 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -4,7 +4,7 @@ import "fmt" // Function call type CallSystemState struct { - prev Fsm + prev State params name string argc uint16 @@ -19,54 +19,54 @@ type CallSystemState struct { ns []uniqueid } -func (a CallSystemState) backward(state Fsm) Fsm { +func (a CallSystemState) backward(state State) State { a.deferred = append(a.deferred, state.(Deferred)) return a } -func (a CallSystemState) Property(name string) Fsm { +func (a CallSystemState) Property(name string) State { return propertyTransition(a, a.params, name, a.deferreds) } -func (a CallSystemState) Func(name string, args []string, invoke string) Fsm { +func (a CallSystemState) Func(name string, args []string, invoke string) State { return funcTransition(a, a.params, name, args, invoke) } -func (a CallSystemState) Bytes(value []byte) Fsm { +func (a CallSystemState) Bytes(value []byte) State { a.deferred = append(a.deferred, a.constant(rideBytes(value))) return a } -func (a CallSystemState) Condition() Fsm { +func (a CallSystemState) Condition() State { return conditionalTransition(a, a.params, a.deferreds) } -func (a CallSystemState) TrueBranch() Fsm { +func (a CallSystemState) TrueBranch() State { panic("Illegal call `TrueBranch` on CallFsm") } -func (a CallSystemState) FalseBranch() Fsm { +func (a CallSystemState) FalseBranch() State { panic("Illegal call `FalseBranch` on CallFsm") } -func (a CallSystemState) String(value string) Fsm { +func (a CallSystemState) String(value string) State { a.deferred = append(a.deferred, a.constant(rideString(value))) return a } -func (a CallSystemState) Boolean(value bool) Fsm { +func (a CallSystemState) Boolean(value bool) State { a.deferred = append(a.deferred, a.constant(rideBoolean(value))) return a } -func callTransition(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { +func callTransition(prev State, params params, name string, argc uint16, d Deferreds) State { if _, ok := params.r.getFunc(name); ok { return newCallUserFsm(prev, params, name, argc, d) } return newCallSystemFsm(prev, params, name, argc, d) } -func newCallSystemFsm(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { +func newCallSystemFsm(prev State, params params, name string, argc uint16, d Deferreds) State { var ns []uniqueid for i := uint16(0); i < argc; i++ { ns = append(ns, params.u.next()) @@ -83,17 +83,17 @@ func newCallSystemFsm(prev Fsm, params params, name string, argc uint16, d Defer } } -func (a CallSystemState) Assigment(name string) Fsm { +func (a CallSystemState) Assigment(name string) State { n := a.params.u.next() return assigmentFsmTransition(a, a.params, name, n, a.deferreds) } -func (a CallSystemState) Long(value int64) Fsm { +func (a CallSystemState) Long(value int64) State { a.deferred = append(a.deferred, a.constant(rideInt(value))) return a } -func (a CallSystemState) Return() Fsm { +func (a CallSystemState) Return() State { if len(a.ns) != len(a.deferred) { panic(fmt.Sprintf("ns %d != a.deferred %d", a.argc, len(a.deferred))) @@ -110,11 +110,11 @@ func (a CallSystemState) Return() Fsm { return a.prev.backward(a) } -func (a CallSystemState) Call(name string, argc uint16) Fsm { +func (a CallSystemState) Call(name string, argc uint16) State { return callTransition(a, a.params, name, argc, a.deferreds) } -func (a CallSystemState) Reference(name string) Fsm { +func (a CallSystemState) Reference(name string) State { a.deferred = append(a.deferred, reference(a, a.params, name)) return a } @@ -123,7 +123,7 @@ func (a CallSystemState) Clean() { } -func (a CallSystemState) Write(_ params, b []byte) { +func (a CallSystemState) Write(_ params, _ []byte) { if int(a.argc) != len(a.deferred) { panic(fmt.Sprintf("argc %d != a.deferred %d", a.argc, len(a.deferred))) } diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index 4bc3342d07..aec74aeff1 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -4,7 +4,7 @@ import "fmt" // Function call type CallUserState struct { - prev Fsm + prev State params name string argc uint16 @@ -14,7 +14,7 @@ type CallUserState struct { ns []uniqueid } -func (a CallUserState) backward(state Fsm) Fsm { +func (a CallUserState) backward(state State) State { num := len(a.ns) n := a.params.u.next() a.ns = append(a.ns, n) @@ -22,7 +22,7 @@ func (a CallUserState) backward(state Fsm) Fsm { return a } -func newCallUserFsm(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm { +func newCallUserFsm(prev State, params params, name string, argc uint16, d Deferreds) State { return &CallUserState{ prev: prev, params: params, @@ -33,64 +33,63 @@ func newCallUserFsm(prev Fsm, params params, name string, argc uint16, d Deferre } } -func (a CallUserState) Property(name string) Fsm { +func (a CallUserState) Property(name string) State { return propertyTransition(a, a.params, name, a.deferreds) } -func (a CallUserState) Func(name string, args []string, invoke string) Fsm { +func (a CallUserState) Func(name string, args []string, invoke string) State { return funcTransition(a, a.params, name, args, invoke) } -func (a CallUserState) Bytes(b []byte) Fsm { +func (a CallUserState) Bytes(b []byte) State { cons := a.constant(rideBytes(b)) a.ns = append(a.ns, cons.n) return a } -func (a CallUserState) Condition() Fsm { +func (a CallUserState) Condition() State { return conditionalTransition(a, a.params, a.deferreds) } -func (a CallUserState) TrueBranch() Fsm { - panic("Illegal call `TrueBranch` on CallFsm") +func (a CallUserState) TrueBranch() State { + panic("Illegal call `TrueBranch` on CallUserState") } -func (a CallUserState) FalseBranch() Fsm { - panic("Illegal call `FalseBranch` on CallFsm") +func (a CallUserState) FalseBranch() State { + panic("Illegal call `FalseBranch` on CallUserState") } -func (a CallUserState) String(s string) Fsm { +func (a CallUserState) String(s string) State { cons := a.constant(rideString(s)) a.ns = append(a.ns, cons.n) return a } -func (a CallUserState) Boolean(v bool) Fsm { +func (a CallUserState) Boolean(v bool) State { cons := a.constant(rideBoolean(v)) a.ns = append(a.ns, cons.n) return a } -func (a CallUserState) Assigment(name string) Fsm { - //return assigmentFsmTransition(a, a.params, name) +func (a CallUserState) Assigment(string) State { panic("CallUserState Assigment") } -func (a CallUserState) Long(value int64) Fsm { +func (a CallUserState) Long(value int64) State { cons := a.constant(rideInt(value)) a.ns = append(a.ns, cons.n) return a } -func (a CallUserState) Return() Fsm { +func (a CallUserState) Return() State { return a.prev.backward(a) } -func (a CallUserState) Call(name string, argc uint16) Fsm { +func (a CallUserState) Call(name string, argc uint16) State { return callTransition(a, a.params, name, argc, a.deferreds) } -func (a CallUserState) Reference(name string) Fsm { +func (a CallUserState) Reference(name string) State { cons := reference(a, a.params, name) a.ns = append(a.ns, cons.n) return a diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 4bfcfbadd3..2ab2d7f1ac 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -7,7 +7,7 @@ import "fmt" // If-else statement. type ConditionalState struct { params - prev Fsm + prev State /* Offset where true branch starts execution. We need this because code can look like: @@ -36,7 +36,7 @@ type ConditionalState struct { condN uniqueid } -func (a ConditionalState) backward(as Fsm) Fsm { +func (a ConditionalState) backward(as State) State { // Func in func. if f, ok := as.(FuncState); ok { a.deferreds.Add(as.(Deferred), f.n, fmt.Sprintf("func `%s`in conditional", f.name)) @@ -46,21 +46,21 @@ func (a ConditionalState) backward(as Fsm) Fsm { return a } -func (a ConditionalState) Property(name string) Fsm { +func (a ConditionalState) Property(name string) State { return propertyTransition(a, a.params, name, a.deferreds) } -func (a ConditionalState) Func(name string, args []string, invoke string) Fsm { +func (a ConditionalState) Func(name string, args []string, invoke string) State { //panic(fmt.Sprintf("Illegal call Func on ConditionalState %s", a.txID)) return funcTransition(a, a.params, name, args, invoke) } -func (a ConditionalState) Bytes(value []byte) Fsm { +func (a ConditionalState) Bytes(value []byte) State { a.deferred = append(a.deferred, a.constant(rideBytes(value))) return a } -func conditionalTransition(prev Fsm, params params, deferreds Deferreds) Fsm { +func conditionalTransition(prev State, params params, deferreds Deferreds) State { return ConditionalState{ prev: prev, params: params, @@ -70,51 +70,51 @@ func conditionalTransition(prev Fsm, params params, deferreds Deferreds) Fsm { } } -func (a ConditionalState) Condition() Fsm { +func (a ConditionalState) Condition() State { a.rets = append(a.rets, a.params.b.len()) return conditionalTransition(a, a.params, a.deferreds) } -func (a ConditionalState) TrueBranch() Fsm { +func (a ConditionalState) TrueBranch() State { return a } -func (a ConditionalState) FalseBranch() Fsm { +func (a ConditionalState) FalseBranch() State { return a } -func (a ConditionalState) Assigment(name string) Fsm { +func (a ConditionalState) Assigment(name string) State { n := a.params.u.next() //a.assigments = append(a.assigments, n) a.r.setAssigment(name, n) return assigmentFsmTransition(a, a.params, name, n, a.deferreds) } -func (a ConditionalState) Long(value int64) Fsm { +func (a ConditionalState) Long(value int64) State { a.deferred = append(a.deferred, a.constant(rideInt(value))) return a } -func (a ConditionalState) Call(name string, argc uint16) Fsm { +func (a ConditionalState) Call(name string, argc uint16) State { return callTransition(a, a.params, name, argc, a.deferreds) } -func (a ConditionalState) Reference(name string) Fsm { +func (a ConditionalState) Reference(name string) State { a.deferred = append(a.deferred, reference(a, a.params, name)) return a } -func (a ConditionalState) Boolean(value bool) Fsm { +func (a ConditionalState) Boolean(value bool) State { a.deferred = append(a.deferred, a.constant(rideBoolean(value))) return a } -func (a ConditionalState) String(value string) Fsm { +func (a ConditionalState) String(value string) State { a.deferred = append(a.deferred, a.constant(rideString(value))) return a } -func (a ConditionalState) Return() Fsm { +func (a ConditionalState) Return() State { if len(a.deferred) < 3 { panic("len(a.deferred) < 3") } @@ -123,7 +123,7 @@ func (a ConditionalState) Return() Fsm { return a.prev.backward(a) } -func (a ConditionalState) Write(_ params, b []byte) { +func (a ConditionalState) Write(_ params, _ []byte) { if len(a.deferred) != 3 { panic("len(a.deferred) != 3") } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 38fee03a13..61f2bd8c35 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -33,7 +33,7 @@ func (a *deferreds) Get() []dd { type FuncState struct { params - prev Fsm + prev State name string args arguments n uniqueid @@ -46,7 +46,7 @@ type FuncState struct { argn int } -func (a FuncState) backward(as Fsm) Fsm { +func (a FuncState) backward(as State) State { // Func in func. if f, ok := as.(FuncState); ok { a.defers.Add(as.(Deferred), f.n, fmt.Sprintf("func `%s`in func %s", f.name, a.name)) @@ -56,11 +56,11 @@ func (a FuncState) backward(as Fsm) Fsm { return a } -func (a FuncState) Property(name string) Fsm { +func (a FuncState) Property(name string) State { return propertyTransition(a, a.params, name, a.defers) } -func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm { +func funcTransition(prev State, params params, name string, args []string, invokeParam string) State { argn := len(args) n := params.u.next() params.r.setFunc(name, n) @@ -94,7 +94,7 @@ func funcTransition(prev Fsm, params params, name string, args []string, invokeP } } -func (a FuncState) Assigment(name string) Fsm { +func (a FuncState) Assigment(name string) State { n := a.params.u.next() return assigmentFsmTransition(a, a.params, name, n, a.defers) } @@ -103,52 +103,52 @@ func (a FuncState) ParamIds() []uniqueid { return a.paramIds } -func (a FuncState) Return() Fsm { +func (a FuncState) Return() State { return a.prev.backward(a) } -func (a FuncState) Long(value int64) Fsm { +func (a FuncState) Long(value int64) State { a.deferred = append(a.deferred, a.constant(rideInt(value))) return a } -func (a FuncState) Call(name string, argc uint16) Fsm { +func (a FuncState) Call(name string, argc uint16) State { return callTransition(a, a.params, name, argc, a.defers) } -func (a FuncState) Reference(name string) Fsm { +func (a FuncState) Reference(name string) State { a.deferred = append(a.deferred, reference(a, a.params, name)) return a } -func (a FuncState) Boolean(value bool) Fsm { +func (a FuncState) Boolean(value bool) State { a.deferred = append(a.deferred, a.constant(rideBoolean(value))) return a } -func (a FuncState) String(value string) Fsm { +func (a FuncState) String(value string) State { a.deferred = append(a.deferred, a.constant(rideString(value))) return a } -func (a FuncState) Condition() Fsm { +func (a FuncState) Condition() State { return conditionalTransition(a, a.params, a.defers) } -func (a FuncState) TrueBranch() Fsm { +func (a FuncState) TrueBranch() State { panic("Illegal call `TrueBranch` on `FuncState`") } -func (a FuncState) FalseBranch() Fsm { +func (a FuncState) FalseBranch() State { panic("Illegal call `FalseBranch` on `FuncState`") } -func (a FuncState) Bytes(value []byte) Fsm { +func (a FuncState) Bytes(value []byte) State { a.deferred = append(a.deferred, a.constant(rideBytes(value))) return a } -func (a FuncState) Func(name string, args []string, invoke string) Fsm { +func (a FuncState) Func(name string, args []string, invoke string) State { return funcTransition(a, a.params, name, args, invoke) } @@ -156,7 +156,7 @@ func (a FuncState) Clean() { } -func (a FuncState) Write(_ params, b []byte) { +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)) if len(a.deferred) != 1 { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index c32d84e1b8..a457222d75 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -8,36 +8,36 @@ type MainState struct { deferreds *deferreds } -func (a MainState) backward(state Fsm) Fsm { +func (a MainState) backward(state State) State { a.body = append(a.body, state.(Deferred)) return a } -func (a MainState) Property(name string) Fsm { +func (a MainState) Property(name string) State { return propertyTransition(a, a.params, name, a.deferreds) } -func (a MainState) Func(name string, args []string, invoke string) Fsm { +func (a MainState) Func(name string, args []string, invoke string) State { return funcTransition(a, a.params, name, args, invoke) } -func (a MainState) Bytes(b []byte) Fsm { +func (a MainState) Bytes([]byte) State { panic("Illegal call `Bytes` on `MainState`") } -func (a MainState) Condition() Fsm { +func (a MainState) Condition() State { return conditionalTransition(a, a.params, a.deferreds) } -func (a MainState) TrueBranch() Fsm { +func (a MainState) TrueBranch() State { panic("Illegal call `TrueBranch` on MainState") } -func (a MainState) FalseBranch() Fsm { +func (a MainState) FalseBranch() State { panic("Illegal call `FalseBranch` on MainState") } -func (a MainState) String(s string) Fsm { +func (a MainState) String(string) State { panic("Illegal call `String` on MainState") } @@ -45,7 +45,7 @@ type BuildExecutable interface { BuildExecutable(version int, isDapp bool, hasVerifier bool) *Executable } -func NewMain(params params) Fsm { +func NewMain(params params) State { return &MainState{ params: params, deferreds: &deferreds{ @@ -54,12 +54,12 @@ func NewMain(params params) Fsm { } } -func (a MainState) Assigment(name string) Fsm { +func (a MainState) Assigment(name string) State { n := a.params.u.next() return assigmentFsmTransition(a, a.params, name, n, a.deferreds) } -func (a MainState) Return() Fsm { +func (a MainState) Return() State { for _, v := range a.deferreds.Get() { v.deferred.Clean() } @@ -96,20 +96,20 @@ func (a MainState) Return() Fsm { return a } -func (a MainState) Long(int64) Fsm { +func (a MainState) Long(int64) State { panic("Illegal call Long on MainState") } -func (a MainState) Call(name string, argc uint16) Fsm { +func (a MainState) Call(name string, argc uint16) State { return callTransition(a, a.params, name, argc, a.deferreds) } -func (a MainState) Reference(name string) Fsm { +func (a MainState) Reference(name string) State { a.body = append(a.body, reference(a, a.params, name)) return a } -func (a MainState) Boolean(v bool) Fsm { +func (a MainState) Boolean(v bool) State { a.body = append(a.body, a.constant(rideBoolean(v))) return a } diff --git a/pkg/ride/compiler_property.go b/pkg/ride/compiler_property.go index cef818bef3..1a0e4fc9c0 100644 --- a/pkg/ride/compiler_property.go +++ b/pkg/ride/compiler_property.go @@ -3,7 +3,7 @@ package ride import "fmt" type PropertyState struct { - prev Fsm + prev State name string params body Deferred @@ -11,12 +11,12 @@ type PropertyState struct { n uniqueid } -func (a PropertyState) backward(as Fsm) Fsm { +func (a PropertyState) backward(as State) State { a.body = as return a } -func propertyTransition(prev Fsm, params params, name string, d Deferreds) Fsm { +func propertyTransition(prev State, params params, name string, d Deferreds) State { return &PropertyState{ params: params, prev: prev, @@ -25,11 +25,11 @@ func propertyTransition(prev Fsm, params params, name string, d Deferreds) Fsm { } } -func (a PropertyState) Assigment(name string) Fsm { +func (a PropertyState) Assigment(string) State { panic("Illegal call `Assigment` on PropertyState") } -func (a PropertyState) Return() Fsm { +func (a PropertyState) Return() State { // 2 possible variations: // 1) tx.id => body is reference // 2) tx.sellOrder.assetPair => body is another property @@ -43,48 +43,48 @@ func (a PropertyState) Return() Fsm { return a.prev.backward(a) } -func (a PropertyState) Long(value int64) Fsm { +func (a PropertyState) Long(int64) State { panic("Illegal call `Long` on PropertyState") } -func (a PropertyState) Call(name string, argc uint16) Fsm { +func (a PropertyState) Call(name string, argc uint16) State { return callTransition(a, a.params, name, argc, a.deferreds) } -func (a PropertyState) Reference(name string) Fsm { +func (a PropertyState) Reference(name string) State { a.body = reference(a, a.params, name) return a } -func (a PropertyState) Boolean(v bool) Fsm { +func (a PropertyState) Boolean(bool) State { panic("Illegal call `Boolean` on PropertyState") } -func (a PropertyState) String(s string) Fsm { +func (a PropertyState) String(string) State { panic("Illegal call `String` on PropertyState") } -func (a PropertyState) Condition() Fsm { +func (a PropertyState) Condition() State { panic("Illegal call `Condition` on PropertyState") } -func (a PropertyState) TrueBranch() Fsm { +func (a PropertyState) TrueBranch() State { panic("Illegal call `TrueBranch` on PropertyState") } -func (a PropertyState) FalseBranch() Fsm { +func (a PropertyState) FalseBranch() State { panic("Illegal call `FalseBranch` on PropertyState") } -func (a PropertyState) Bytes(b []byte) Fsm { +func (a PropertyState) Bytes(b []byte) State { panic("PropertyState Bytes") } -func (a PropertyState) Func(name string, args []string, invoke string) Fsm { +func (a PropertyState) Func(_ string, _ []string, _ string) State { panic("Illegal call `Func` on PropertyState") } -func (a PropertyState) Property(name string) Fsm { +func (a PropertyState) Property(name string) State { return propertyTransition(a, a.params, name, a.deferreds) } diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index f2a11046de..bbb6580f8a 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -2,21 +2,21 @@ package ride import "fmt" -type Fsm interface { - Assigment(name string) Fsm - Return() Fsm - Long(value int64) Fsm - Call(name string, argc uint16) Fsm - Reference(name string) Fsm - Boolean(v bool) Fsm - String(s string) Fsm - Condition() Fsm - TrueBranch() Fsm - FalseBranch() Fsm - Bytes(b []byte) Fsm - Func(name string, args []string, invokeParam string) Fsm - Property(name string) Fsm - backward(state Fsm) Fsm +type State interface { + Assigment(name string) State + Return() State + Long(value int64) State + Call(name string, argc uint16) State + Reference(name string) State + Boolean(v bool) State + String(s string) State + Condition() State + TrueBranch() State + FalseBranch() State + Bytes(b []byte) State + Func(name string, args []string, invokeParam string) State + Property(name string) State + backward(state State) State Deferred } @@ -80,7 +80,7 @@ func (a *params) constant(value rideType) constantDeferred { return NewConstantDeferred(n) } -func reference(_ Fsm, params params, name string) constantDeferred { +func reference(_ State, params params, name string) constantDeferred { pos, ok := params.r.getAssigment(name) if !ok { panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler_test.go similarity index 100% rename from pkg/ride/compiler2_test.go rename to pkg/ride/compiler_test.go diff --git a/pkg/ride/deserializer.go b/pkg/ride/deserializer.go index be325742b5..f230ba18d6 100644 --- a/pkg/ride/deserializer.go +++ b/pkg/ride/deserializer.go @@ -46,9 +46,9 @@ func (a *Deserializer) Bool() (bool, error) { return false, err } switch b { - case strue: + case sTrue: return true, nil - case sfalse: + case sFalse: return false, nil default: return false, errors.New("unknown byte") @@ -115,17 +115,17 @@ func (a *Deserializer) RideValue() (rideType, error) { switch b { case sNoValue: return nil, nil - case strue: + case sTrue: return rideBoolean(true), nil - case sfalse: + case sFalse: return rideBoolean(false), nil - case sint: + case sInt: v, err := a.Int64() return rideInt(v), err case sString: v, err := a.String() return rideString(v), err - case sbytes: + case sBytes: v, err := a.Bytes() return rideBytes(v), err case sAddress: diff --git a/pkg/ride/serializer.go b/pkg/ride/serializer.go index 75f768fbb8..2ee50280e4 100644 --- a/pkg/ride/serializer.go +++ b/pkg/ride/serializer.go @@ -9,11 +9,11 @@ import ( ) const ( - strue byte = 101 - sfalse byte = 102 - sint byte = 103 - suint16 byte = 104 - sbytes byte = 105 + sTrue byte = 101 + sFalse byte = 102 + sInt byte = 103 + sUint16 byte = 104 + sBytes byte = 105 sString byte = 106 sPoint byte = 107 sMap byte = 108 @@ -38,7 +38,7 @@ func (a *Serializer) RideInt(v rideInt) error { a.b.WriteByte(byte(v)) return nil } - a.b.WriteByte(sint) + a.b.WriteByte(sInt) b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) a.b.Write(b) @@ -49,7 +49,7 @@ func (a *Serializer) RideNoValue() error { return a.b.WriteByte(sNoValue) } -func (a *Serializer) Tuple(values ...rideType) error { +func (a *Serializer) Tuple(...rideType) error { panic("not implemented") } @@ -61,9 +61,9 @@ func (a *Serializer) Uint16(v uint16) { func (a *Serializer) Bool(v bool) { if v { - a.b.WriteByte(strue) + a.b.WriteByte(sTrue) } else { - a.b.WriteByte(sfalse) + a.b.WriteByte(sFalse) } } @@ -77,7 +77,7 @@ func (a *Serializer) Byte(b byte) { } func (a *Serializer) RideBytes(v rideBytes) error { - a.b.WriteByte(sbytes) + a.b.WriteByte(sBytes) return a.Bytes(v) } diff --git a/pkg/ride/tree_estimatorV3.go b/pkg/ride/tree_estimatorV3.go index 7c88c611d9..44029fef26 100644 --- a/pkg/ride/tree_estimatorV3.go +++ b/pkg/ride/tree_estimatorV3.go @@ -8,6 +8,7 @@ type fd struct { cost int usages []string } + type fsV3 struct { parent *fsV3 functions map[string]fd diff --git a/pkg/ride/tree_expand.go b/pkg/ride/tree_expand.go index 9d7a287f8c..542c29486b 100644 --- a/pkg/ride/tree_expand.go +++ b/pkg/ride/tree_expand.go @@ -141,6 +141,5 @@ func expand(scope expandScope, node Node) Node { return v default: panic(fmt.Sprintf("unknown %T", node)) - return v.Clone() } } diff --git a/pkg/ride/tree_expand_test.go b/pkg/ride/tree_expand_test.go index 0117b4bf26..a88f4b02b1 100644 --- a/pkg/ride/tree_expand_test.go +++ b/pkg/ride/tree_expand_test.go @@ -222,8 +222,6 @@ func TestExpandScope(t *testing.T) { } func TestExpandSmthWrote(t *testing.T) { - // file_5.ride - //source := `AAIDAAAAAAAAAAQIARIAAAAAIgEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBoAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAEAAAAOZ2V0U3RyaW5nQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABB0AAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABlN0cmluZwQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQIAAAAAAQAAAAxnZXRCb29sQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBsAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAB0Jvb2xlYW4EAAAAAWEFAAAAByRtYXRjaDAFAAAAAWEHAQAAABhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkAAAACAAAAB2FkZHJlc3MAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAAB2FkZHJlc3MFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAAAQAAABZjb252ZXJ0SnNvbkFycmF5VG9MaXN0AAAAAQAAAAlqc29uQXJyYXkJAAS1AAAAAgUAAAAJanNvbkFycmF5AgAAAAEsAAAAAAVCTE9DSwIAAAAFYmxvY2sAAAAACUNPTkZJUk1UWAIAAAAKY29uZmlybV90eAAAAAAKT3JhY2xlc0tleQIAAAAHb3JhY2xlcwAAAAAJQWRtaW5zS2V5AgAAAAZhZG1pbnMAAAAAD1ZvdGVJbnRlcnZhbEtleQIAAAANdm90ZV9pbnRlcnZhbAAAAAAUQ29lZmZpY2llbnRPcmFjbGVLZXkCAAAAEmNvZWZmaWNpZW50X29yYWNsZQAAAAATQ29lZmZpY2llbnRBZG1pbktleQIAAAARY29lZmZpY2llbnRfYWRtaW4AAAAADlByaWNlT2Zmc2V0S2V5AgAAAAxwcmljZV9vZmZzZXQAAAAACFByaWNlS2V5AgAAAAVwcmljZQAAAAAMSXNCbG9ja2VkS2V5AgAAAAppc19ibG9ja2VkAAAAABJCbG9ja0V4cGlyZVZvdGVLZXkCAAAAEXZvdGVfZXhwaXJlX2Jsb2NrAAAAAA1QcmljZUluZGV4S2V5AgAAAAtwcmljZV9pbmRleAAAAAAQTGFzdENvbmZpcm1UeEtleQIAAAAPbGFzdF9jb25maXJtX3R4AQAAAA9nZXRBZG1pblZvdGVLZXkAAAABAAAABW93bmVyCQABLAAAAAICAAAAC2FkbWluX3ZvdGVfBQAAAAVvd25lcgEAAAAYZ2V0QWRtaW5Wb3RlQXJndW1lbnRzS2V5AAAAAQAAAAVvd25lcgkAASwAAAACCQABLAAAAAICAAAADHZvdGVfYWN0aW9uXwUAAAAFb3duZXICAAAACl9hcmd1bWVudHMBAAAAFWdldEJsYWNrU3dhcm1QcmljZUtleQAAAAEAAAAFYmxvY2sJAAEsAAAAAgkAASwAAAACAgAAABFibGFja19zd2FybV9wcmljZQIAAAABXwkAAaQAAAABBQAAAAVibG9jawEAAAASZ2V0UHJpY2VIaXN0b3J5S2V5AAAAAQAAAAVibG9jawkAASwAAAACCQABLAAAAAIFAAAACFByaWNlS2V5AgAAAAFfCQABpAAAAAEFAAAABWJsb2NrAQAAABhnZXRIZWlnaHRQcmljZUJ5SW5kZXhLZXkAAAABAAAABWluZGV4CQABLAAAAAIJAAEsAAAAAgUAAAANUHJpY2VJbmRleEtleQIAAAABXwkAAaQAAAABBQAAAAVpbmRleAEAAAAYZ2V0T3JhY2xlUHJvdmlkZVByaWNlS2V5AAAAAQAAAAZoZWlnaHQJAAEsAAAAAgIAAAAGcHJpY2VfCQABpAAAAAEFAAAABmhlaWdodAAAAAAFcHJpY2UJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEFAAAACFByaWNlS2V5AAAAAApwcmljZUluZGV4CQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABBQAAAA1QcmljZUluZGV4S2V5AAAAAAlpc0Jsb2NrZWQJAQAAAAxnZXRCb29sQnlLZXkAAAABBQAAAAxJc0Jsb2NrZWRLZXkAAAAAFGJmdENvZWZmaWNpZW50T3JhY2xlCQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABBQAAABRDb2VmZmljaWVudE9yYWNsZUtleQAAAAAScGVyY2VudFByaWNlT2Zmc2V0CQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABBQAAAA5QcmljZU9mZnNldEtleQAAAAAHb3JhY2xlcwkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQUAAAAKT3JhY2xlc0tleQAAAAALb3JhY2xlc0xpc3QJAQAAABZjb252ZXJ0SnNvbkFycmF5VG9MaXN0AAAAAQUAAAAHb3JhY2xlcwAAAAANbGFzdENvbmZpcm1UeAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQUAAAAQTGFzdENvbmZpcm1UeEtleQEAAAAWZ2V0T3JhY2xlUHJvdmlkZUhlaWdodAAAAAIAAAAFb3duZXIAAAAGaGVpZ2h0CQEAAAAYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AAAAAgkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABBQAAAAVvd25lcgkBAAAAGGdldE9yYWNsZVByb3ZpZGVQcmljZUtleQAAAAEFAAAABmhlaWdodAEAAAAPZ2V0UHJpY2VIaXN0b3J5AAAAAQAAAAZoZWlnaHQJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEJAQAAABJnZXRQcmljZUhpc3RvcnlLZXkAAAABBQAAAAZoZWlnaHQAAAABAAAAAWkBAAAAFGZpbmFsaXplQ3VycmVudFByaWNlAAAAAAQAAAAGcHJpY2VzCQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAAUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAQUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAgUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAAAwUAAAAGaGVpZ2h0CQAETAAAAAIJAQAAABZnZXRPcmFjbGVQcm92aWRlSGVpZ2h0AAAAAgkAAZEAAAACBQAAAAtvcmFjbGVzTGlzdAAAAAAAAAAABAUAAAAGaGVpZ2h0BQAAAANuaWwEAAAAE3ByaWNlUHJvdmlkaW5nQ291bnQJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAABkAAAAAgMJAQAAAAIhPQAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAwkBAAAAAiE9AAAAAgkAAZEAAAACBQAAAAZwcmljZXMAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAADCQEAAAACIT0AAAACCQABkQAAAAIFAAAABnByaWNlcwAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAMJAQAAAAIhPQAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAwkBAAAAAiE9AAAAAgkAAZEAAAACBQAAAAZwcmljZXMAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAEAAAACHByaWNlU3VtCQAAZAAAAAIJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAAACQABkQAAAAIFAAAABnByaWNlcwAAAAAAAAAAAQkAAZEAAAACBQAAAAZwcmljZXMAAAAAAAAAAAIJAAGRAAAAAgUAAAAGcHJpY2VzAAAAAAAAAAADCQABkQAAAAIFAAAABnByaWNlcwAAAAAAAAAABAQAAAAIbmV3UHJpY2UJAABpAAAAAgUAAAAIcHJpY2VTdW0FAAAAE3ByaWNlUHJvdmlkaW5nQ291bnQDBQAAAAlpc0Jsb2NrZWQJAAACAAAAAQIAAAATY29udHJhY3QgaXMgYmxvY2tlZAMJAQAAAAIhPQAAAAIJAQAAAA9nZXRQcmljZUhpc3RvcnkAAAABBQAAAAZoZWlnaHQAAAAAAAAAAAAJAAACAAAAAQIAAAAPd2FpdCBuZXh0IGJsb2NrAwkAAGYAAAACBQAAABRiZnRDb2VmZmljaWVudE9yYWNsZQUAAAATcHJpY2VQcm92aWRpbmdDb3VudAkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABpAAAAAEFAAAAFGJmdENvZWZmaWNpZW50T3JhY2xlAgAAACAvNSBvcmFjbGVzIG5lZWQgdG8gc2V0IGEgcHJpY2UgKAkAAaQAAAABBQAAABNwcmljZVByb3ZpZGluZ0NvdW50AgAAAAEpAwMJAABnAAAAAgUAAAAIbmV3UHJpY2UJAABkAAAAAgUAAAAFcHJpY2UJAABpAAAAAgkAAGgAAAACBQAAAAVwcmljZQUAAAAScGVyY2VudFByaWNlT2Zmc2V0AAAAAAAAAABkBgkAAGcAAAACCQAAZQAAAAIFAAAABXByaWNlCQAAaQAAAAIJAABoAAAAAgUAAAAFcHJpY2UFAAAAEnBlcmNlbnRQcmljZU9mZnNldAAAAAAAAAAAZAUAAAAIbmV3UHJpY2UJAQAAAAhXcml0ZVNldAAAAAEJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIFAAAADElzQmxvY2tlZEtleQYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIJAQAAABVnZXRCbGFja1N3YXJtUHJpY2VLZXkAAAABBQAAAAZoZWlnaHQFAAAACG5ld1ByaWNlBQAAAANuaWwEAAAADW5ld1ByaWNlSW5kZXgJAABkAAAAAgUAAAAKcHJpY2VJbmRleAAAAAAAAAAAAQkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAAIUHJpY2VLZXkFAAAACG5ld1ByaWNlCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACCQEAAAASZ2V0UHJpY2VIaXN0b3J5S2V5AAAAAQUAAAAGaGVpZ2h0BQAAAAhuZXdQcmljZQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgUAAAANUHJpY2VJbmRleEtleQUAAAANbmV3UHJpY2VJbmRleAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkBAAAAGGdldEhlaWdodFByaWNlQnlJbmRleEtleQAAAAEFAAAADW5ld1ByaWNlSW5kZXgFAAAABmhlaWdodAUAAAADbmlsAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAAAAAAACBQAAAA1sYXN0Q29uZmlybVR4CQACWAAAAAEIBQAAAAJ0eAAAAAJpZK4nr/0=` source := `AAIDAAAAAAAAAAQIARIAAAAAAwEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABAAAAA2tleQMJAAAAAAAAAgUAAAADa2V5AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAEmdldFByaWNlSGlzdG9yeUtleQAAAAEAAAAFYmxvY2sJAAEsAAAAAgIAAAAGcHJpY2VfCQABpAAAAAEFAAAABWJsb2NrAQAAAA9nZXRQcmljZUhpc3RvcnkAAAABAAAABmhlaWdodAkBAAAADmdldE51bWJlckJ5S2V5AAAAAQkBAAAAEmdldFByaWNlSGlzdG9yeUtleQAAAAEFAAAABmhlaWdodAAAAAEAAAABaQEAAAAUZmluYWxpemVDdXJyZW50UHJpY2UAAAAAAwkBAAAAAiE9AAAAAgkBAAAAD2dldFByaWNlSGlzdG9yeQAAAAEFAAAABmhlaWdodAAAAAAAAAAAAAkAAAIAAAABAgAAAA93YWl0IG5leHQgYmxvY2sJAQAAAAhXcml0ZVNldAAAAAEFAAAAA25pbAAAAACFlzmA` src, err := base64.StdEncoding.DecodeString(source) @@ -266,23 +264,9 @@ func TestExpandSmthWrote(t *testing.T) { if bytes.Equal([]byte{1, 83, 136, 55, 96, 43, 245, 23, 100, 121, 143, 9, 41, 146, 104, 231, 155, 80, 89, 107, 191, 124, 84, 104, 99, 235}, account.Address.Bytes()) && key == "price_209553" { return nil, errors.New("not found") } - panic(fmt.Sprintf("RetrieveNewestIntegerEntryFunc %+v %s", account.Address.Bytes(), key)) - //if !bytes.Equal(account.Address.Bytes(), this) { - // panic("unknown account " + account.String()) - //} - // - //switch key { - //case "coefficient_oracle": - // return &proto.IntegerDataEntry{Key: key, Value: 3}, nil - //case "price_209553": - // return &proto.IntegerDataEntry{Key: key, Value: 60}, nil - //default: - // panic("unknown key " + key) - //} }, RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { - //case "is_blocked": return nil, errors.New(key + " not found") }, // 1053 @@ -327,6 +311,5 @@ func TestExpandSmthWrote(t *testing.T) { rs, err := script.Invoke(env, "finalizeCurrentPrice", nil) require.NoError(t, err) - //require.Equal(t, 2, len(rs.Calls())) - require.Equal(t, true, rs.Result()) + require.Equal(t, false, rs.Result()) } diff --git a/pkg/ride/vm_test.go b/pkg/ride/vm_test.go index ad41be5bd3..5425ddb878 100644 --- a/pkg/ride/vm_test.go +++ b/pkg/ride/vm_test.go @@ -1,19 +1,12 @@ package ride import ( - "bytes" - "encoding/base64" "encoding/json" - "testing" "time" "github.com/mr-tron/base58" - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" - "github.com/wavesplatform/gowaves/pkg/types" "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" ) @@ -128,309 +121,6 @@ func newDataTransaction() *proto.DataWithProofs { return tx } -func TestFunctions(t *testing.T) { - t.SkipNow() - d, err := crypto.NewDigestFromBase58("BXBUNddxTGTQc3G4qHYn5E67SBwMj18zLncUr871iuRD") - transfer := newTransferTransaction() - exchange := newExchangeTransaction() - data := newDataTransaction() - require.NoError(t, err) - env := &MockRideEnvironment{ - checkMessageLengthFunc: v3check, - schemeFunc: func() byte { - return 'W' - }, - heightFunc: func() rideInt { - return 5 - }, - transactionFunc: func() rideObject { - obj, err := transferWithProofsToObject('W', transfer) - if err != nil { - panic(err) - } - return obj - }, - stateFunc: func() types.SmartState { - return &MockSmartState{ - RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { - if key == "integer" { - return &proto.IntegerDataEntry{Key: "integer", Value: 100500}, nil - } - return nil, errors.New("not found") - }, - RetrieveNewestBooleanEntryFunc: func(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { - if key == "boolean" { - return &proto.BooleanDataEntry{Key: "boolean", Value: true}, nil - } - return nil, errors.New("not found") - }, - RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { - if key == "binary" { - return &proto.BinaryDataEntry{Key: "binary", Value: []byte("hello")}, nil - } - return nil, errors.New("not found") - }, - RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { - if key == "string" { - return &proto.StringDataEntry{Key: "string", Value: "world"}, nil - } - return nil, errors.New("not found") - }, - NewestAccountBalanceFunc: func(account proto.Recipient, asset []byte) (uint64, error) { - if len(asset) == 0 { - return 5, nil - } else { - if bytes.Equal(asset, d.Bytes()) { - return 5, nil - } - return 0, nil - } - }, - NewestTransactionByIDFunc: func(id []byte) (proto.Transaction, error) { - return transfer, nil - }, - NewestTransactionHeightByIDFunc: func(_ []byte) (uint64, error) { - return 0, proto.ErrNotFound - }, - IsNotFoundFunc: func(err error) bool { - return true - }, - } - }, - } - _ /*envWithDataTX :*/ = &MockRideEnvironment{ - transactionFunc: func() rideObject { - obj, err := dataWithProofsToObject('W', data) - if err != nil { - panic(err) - } - return obj - }, - } - envWithExchangeTX := &MockRideEnvironment{ - transactionFunc: func() rideObject { - obj, err := exchangeWithProofsToObject('W', exchange) - if err != nil { - panic(err) - } - return obj - }, - } - for _, test := range []struct { - name string - text string - script string - env RideEnvironment - result bool - error bool - }{ - //{`parseIntValue`, `parseInt("12345") == 12345`, `AwkAAAAAAAACCQAEtgAAAAECAAAABTEyMzQ1AAAAAAAAADA57cmovA==`, nil, true, false}, - //{`value`, `let c = if true then 1 else Unit(); value(c) == 1`, `AwQAAAABYwMGAAAAAAAAAAABCQEAAAAEVW5pdAAAAAAJAAAAAAAAAgkBAAAABXZhbHVlAAAAAQUAAAABYwAAAAAAAAAAARfpQ5M=`, nil, true, false}, - //{`valueOrErrorMessage`, `let c = if true then 1 else Unit(); valueOrErrorMessage(c, "ALARM!!!") == 1`, `AwQAAAABYwMGAAAAAAAAAAABCQEAAAAEVW5pdAAAAAAJAAAAAAAAAgkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACBQAAAAFjAgAAAAhBTEFSTSEhIQAAAAAAAAAAAa5tVyw=`, nil, true, false}, - //{`addressFromString`, `addressFromString("12345") == unit`, `AwkAAAAAAAACCQEAAAARYWRkcmVzc0Zyb21TdHJpbmcAAAABAgAAAAUxMjM0NQUAAAAEdW5pdJEPLPE=`, env, true, false}, - //{`addressFromString`, `addressFromString("3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc") == Address(base58'3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc')`, `AwkAAAAAAAACCQEAAAARYWRkcmVzc0Zyb21TdHJpbmcAAAABAgAAACMzUDlERURQNVZieVhReUt0WERVdDJjclJQbjVCN2dzNnVqYwkBAAAAB0FkZHJlc3MAAAABAQAAABoBV0/fzRv7GRFL0qw2njIBPHDG0DpGJ4ecv6EI6ng=`, env, true, false}, - //{`addressFromStringValue`, `addressFromStringValue("3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc") == Address(base58'3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc')`, `AwkAAAAAAAACCQEAAAAcQGV4dHJVc2VyKGFkZHJlc3NGcm9tU3RyaW5nKQAAAAECAAAAIzNQOURFRFA1VmJ5WFF5S3RYRFV0MmNyUlBuNUI3Z3M2dWpjCQEAAAAHQWRkcmVzcwAAAAEBAAAAGgFXT9/NG/sZEUvSrDaeMgE8cMbQOkYnh5y/56rYHQ==`, env, true, false}, - //{`getIntegerFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getInteger(a, "integer") == 100500`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQAEGgAAAAIFAAAAAWECAAAAB2ludGVnZXIAAAAAAAABiJTtgrwb`, env, true, false}, - //{`getIntegerValueFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getIntegerValue(a, "integer") == 100500`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAAFhAgAAAAdpbnRlZ2VyAAAAAAAAAYiUEnGoww==`, env, true, false}, - //{`getBooleanFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getBoolean(a, "boolean") == true`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQAEGwAAAAIFAAAAAWECAAAAB2Jvb2xlYW4GQ1SwZw==`, env, true, false}, - //{`getBooleanValueFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getBooleanValue(a, "boolean") == true`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA1MSkAAAACBQAAAAFhAgAAAAdib29sZWFuBiG4UlQ=`, env, true, false}, - //{`getBinaryFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getBinary(a, "binary") == base16'68656c6c6f'`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQAEHAAAAAIFAAAAAWECAAAABmJpbmFyeQEAAAAFaGVsbG8AbKgo`, env, true, false}, - //{`getBinaryValueFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getBinaryValue(a, "binary") == base16'68656c6c6f'`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA1MikAAAACBQAAAAFhAgAAAAZiaW5hcnkBAAAABWhlbGxvJ1b3yw==`, env, true, false}, - //{`getStringFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getString(a, "string") == "world"`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA1MikAAAACBQAAAAFhAgAAAAZiaW5hcnkBAAAABWhlbGxvJ1b3yw==`, env, true, false}, - //{`getStringValueFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); getStringValue(a, "string") == "world"`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwkAAAAAAAACCQAEHQAAAAIFAAAAAWECAAAABnN0cmluZwIAAAAFd29ybGSFdQnb`, env, true, false}, - //{`getIntegerFromArrayByKey`, `let d = [DataEntry("integer", 100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getInteger(d, "integer") == 100500`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQAEEAAAAAIFAAAAAWQCAAAAB2ludGVnZXIAAAAAAAABiJSeStXa`, env, true, false}, - //{`getIntegerValueFromArrayByKey`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getIntegerValue(d, "integer") == 100500`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA0MCkAAAACBQAAAAFkAgAAAAdpbnRlZ2VyAAAAAAAAAYiUmn7ujg==`, env, true, false}, - //{`getBooleanFromArrayByKey`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBoolean(d, "boolean") == true`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQAEEQAAAAIFAAAAAWQCAAAAB2Jvb2xlYW4GaWuehg==`, env, true, false}, - //{`getBooleanValueFromArrayByKey`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBooleanValue(d, "boolean") == true`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA0MSkAAAACBQAAAAFkAgAAAAdib29sZWFuBt3vwJY=`, env, true, false}, - //{`getBinaryFromArrayByKey`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBinary(d, "binary") == base16'68656c6c6f'`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQAEEgAAAAIFAAAAAWQCAAAABmJpbmFyeQEAAAAFaGVsbG+so7oZ`, env, true, false}, - //{`getBinaryValueFromArrayByKey`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBinaryValue(d, "binary") == base16'68656c6c6f'`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA0MikAAAACBQAAAAFkAgAAAAZiaW5hcnkBAAAABWhlbGxvpcldYg==`, env, true, false}, - //{`getStringFromArrayByKey`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getString(d, "string") == "world"`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQAEEwAAAAIFAAAAAWQCAAAABnN0cmluZwIAAAAFd29ybGRFTMLs`, env, true, false}, - //{`getStringValueFromArrayByKey`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getStringValue(d, "string") == "world"`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAARQGV4dHJOYXRpdmUoMTA0MykAAAACBQAAAAFkAgAAAAZzdHJpbmcCAAAABXdvcmxkCbSDLQ==`, env, true, false}, - //{`getIntegerFromArrayByIndex`, `let d = [DataEntry("integer", 100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getInteger(d, 0) == 100500`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAKZ2V0SW50ZWdlcgAAAAIFAAAAAWQAAAAAAAAAAAAAAAAAAAABiJTdCjRc`, env, true, false}, - //{`getIntegerValueFromArrayByIndex`, `let d = [DataEntry("integer", 100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getIntegerValue(d, 0) == 100500`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAVQGV4dHJVc2VyKGdldEludGVnZXIpAAAAAgUAAAABZAAAAAAAAAAAAAAAAAAAAAGIlOyDHCY=`, env, true, false}, - //{`getBooleanFromArrayByIndex`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBoolean(d, 1) == true`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAKZ2V0Qm9vbGVhbgAAAAIFAAAAAWQAAAAAAAAAAAEGlS0yug==`, env, true, false}, - //{`getBooleanValueFromArrayByIndex`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBooleanValue(d, 1) == true`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAVQGV4dHJVc2VyKGdldEJvb2xlYW4pAAAAAgUAAAABZAAAAAAAAAAAAQY8zZ6Y`, env, true, false}, - //{`getBinaryFromArrayByIndex`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBinary(d, 2) == base16'68656c6c6f'`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAJZ2V0QmluYXJ5AAAAAgUAAAABZAAAAAAAAAAAAgEAAAAFaGVsbG/jc7GJ`, env, true, false}, - //{`getBinaryValueFromArrayByIndex`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getBinaryValue(d, 2) == base16'68656c6c6f'`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAUQGV4dHJVc2VyKGdldEJpbmFyeSkAAAACBQAAAAFkAAAAAAAAAAACAQAAAAVoZWxsbwxEPw4=`, env, true, false}, - //{`getStringFromArrayByIndex`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getString(d, 3) == "world"`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAJZ2V0U3RyaW5nAAAAAgUAAAABZAAAAAAAAAAAAwIAAAAFd29ybGTcG8rI`, env, true, false}, - //{`getStringValueFromArrayByIndex`, `let d = [DataEntry("integer",100500), DataEntry("boolean", true), DataEntry("binary", base16'68656c6c6f'), DataEntry("string", "world")]; getStringValue(d, 3) == "world"`, `AwQAAAABZAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHaW50ZWdlcgAAAAAAAAGIlAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgIAAAAHYm9vbGVhbgYJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABmJpbmFyeQEAAAAFaGVsbG8JAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAICAAAABnN0cmluZwIAAAAFd29ybGQFAAAAA25pbAkAAAAAAAACCQEAAAAUQGV4dHJVc2VyKGdldFN0cmluZykAAAACBQAAAAFkAAAAAAAAAAADAgAAAAV3b3JsZOGBO8c=`, env, true, false}, - //{`compare Recipient with Address`, `let a = Address(base58'3PKpKgcwArHQVmYWUg6Ljxx31VueBStUKBR'); match tx {case tt: TransferTransaction => tt.recipient == a case _ => false}`, `AwQAAAABYQkBAAAAB0FkZHJlc3MAAAABAQAAABoBV8Q0LvvkEO83LtpdRUhgK760itMpcq1W7AQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAnR0BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0dAAAAAlyZWNpcGllbnQFAAAAAWEHQOLkRA==`, env, false, false}, - //{`compare Recipient with Address`, `let a = Address(base58'3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3'); match tx {case tt: TransferTransaction => tt.recipient == a case _ => false}`, `AwQAAAABYQkBAAAAB0FkZHJlc3MAAAABAQAAABoBVwX3L9Q7Ao0/8ZNhoE70/41bHPBwqbd27gQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAnR0BQAAAAckbWF0Y2gwCQAAAAAAAAIIBQAAAAJ0dAAAAAlyZWNpcGllbnQFAAAAAWEHd9vYmA==`, env, true, false}, - //{`compare Address with Recipient`, `let a = Address(base58'3PKpKgcwArHQVmYWUg6Ljxx31VueBStUKBR'); match tx {case tt: TransferTransaction => a == tt.recipient case _ => false}`, `AwQAAAABYQkBAAAAB0FkZHJlc3MAAAABAQAAABoBV8Q0LvvkEO83LtpdRUhgK760itMpcq1W7AQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAnR0BQAAAAckbWF0Y2gwCQAAAAAAAAIFAAAAAWEIBQAAAAJ0dAAAAAlyZWNpcGllbnQHG1tX4w==`, env, false, false}, - //{`compare Address with Recipient`, `let a = Address(base58'3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3'); match tx {case tt: TransferTransaction => a == tt.recipient case _ => false}`, `AwQAAAABYQkBAAAAB0FkZHJlc3MAAAABAQAAABoBVwX3L9Q7Ao0/8ZNhoE70/41bHPBwqbd27gQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAnR0BQAAAAckbWF0Y2gwCQAAAAAAAAIFAAAAAWEIBQAAAAJ0dAAAAAlyZWNpcGllbnQHw8RWfw==`, env, true, false}, - // - //{`getIntegerFromDataTransactionByKey`, `match tx {case d: DataTransaction => extract(getInteger(d.data, "integer")) == 100500 case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAD0RhdGFUcmFuc2FjdGlvbgQAAAABZAUAAAAHJG1hdGNoMAkAAAAAAAACCQEAAAAHZXh0cmFjdAAAAAEJAAQQAAAAAggFAAAAAWQAAAAEZGF0YQIAAAAHaW50ZWdlcgAAAAAAAAGIlAfN4Sfl`, envWithDataTX, true, false}, - //{`getIntegerFromDataTransactionByKey`, `match tx {case dt: DataTransaction => let a = match getInteger(dt.data, "someKey") {case v: Int => v case _ => -1}; a >= 0 case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAD0RhdGFUcmFuc2FjdGlvbgQAAAACZHQFAAAAByRtYXRjaDAEAAAAAWEEAAAAByRtYXRjaDEJAAQQAAAAAggFAAAAAmR0AAAABGRhdGECAAAAB3NvbWVLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDECAAAAA0ludAQAAAABdgUAAAAHJG1hdGNoMQUAAAABdgD//////////wkAAGcAAAACBQAAAAFhAAAAAAAAAAAAB1mStww=`, envWithDataTX, true, false}, - //{`getIntegerFromDataTransactionByKey`, `match tx {case dt: DataTransaction => let x = match getInteger(dt.data, "someKey") {case i: Int => true case _ => false};let y = match getInteger(dt.data, "someKey") {case v: Int => v case _ => -1}; x && y >= 0 case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAD0RhdGFUcmFuc2FjdGlvbgQAAAACZHQFAAAAByRtYXRjaDAEAAAAAXgEAAAAByRtYXRjaDEJAAQQAAAAAggFAAAAAmR0AAAABGRhdGECAAAAB3NvbWVLZXkDCQAAAQAAAAIFAAAAByRtYXRjaDECAAAAA0ludAQAAAABaQUAAAAHJG1hdGNoMQYHBAAAAAF5BAAAAAckbWF0Y2gxCQAEEAAAAAIIBQAAAAJkdAAAAARkYXRhAgAAAAdzb21lS2V5AwkAAAEAAAACBQAAAAckbWF0Y2gxAgAAAANJbnQEAAAAAXYFAAAAByRtYXRjaDEFAAAAAXYA//////////8DBQAAAAF4CQAAZwAAAAIFAAAAAXkAAAAAAAAAAAAHB5sznFY=`, envWithDataTX, true, false}, - //{`matchIntegerFromDataTransactionByKey`, `let x = match tx {case d: DataTransaction => match getInteger(d.data, "integer") {case i: Int => i case _ => 0}case _ => 0}; x == 100500`, `AQQAAAABeAQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAD0RhdGFUcmFuc2FjdGlvbgQAAAABZAUAAAAHJG1hdGNoMAQAAAAHJG1hdGNoMQkABBAAAAACCAUAAAABZAAAAARkYXRhAgAAAAdpbnRlZ2VyAwkAAAEAAAACBQAAAAckbWF0Y2gxAgAAAANJbnQEAAAAAWkFAAAAByRtYXRjaDEFAAAAAWkAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAgUAAAABeAAAAAAAAAGIlApOoB4=`, envWithDataTX, true, false}, - //{`matchIntegerFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); let i = getInteger(a, "integer"); let x = match i {case i: Int => i case _ => 0}; x == 100500`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwQAAAABaQkABBoAAAACBQAAAAFhAgAAAAdpbnRlZ2VyBAAAAAF4BAAAAAckbWF0Y2gwBQAAAAFpAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAAWkFAAAAByRtYXRjaDAFAAAAAWkAAAAAAAAAAAAJAAAAAAAAAgUAAAABeAAAAAAAAAGIlKWtlDk=`, env, true, false}, - //{`ifIntegerFromState`, `let a = addressFromStringValue("3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"); let i = getInteger(a, "integer"); let x = if i != 0 then i else 0; x == 100500`, `AwQAAAABYQkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABAgAAACMzUDJVU0UzaVlLNXc3ak5haEFVSFR5dE5iVlJjY0dad1FIMwQAAAABaQkABBoAAAACBQAAAAFhAgAAAAdpbnRlZ2VyBAAAAAF4AwkBAAAAAiE9AAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQAAAAAAAAAAAAkAAAAAAAACBQAAAAF4AAAAAAAAAYiU1cZgMA==`, env, true, false}, - // - //{`string concatenation`, `let a = base16'cafe'; let b = base16'bebe'; toBase58String(a) + "/" + toBase58String(b) == "GSy/FWu"`, `AwQAAAABYQEAAAACyv4EAAAAAWIBAAAAAr6+CQAAAAAAAAIJAAEsAAAAAgkAASwAAAACCQACWAAAAAEFAAAAAWECAAAAAS8JAAJYAAAAAQUAAAABYgIAAAAHR1N5L0ZXdc2NqKQ=`, env, true, false}, - //{`match on ByteVector`, `match tx {case etx: ExchangeTransaction => match etx.sellOrder.assetPair.amountAsset {case ByteVector => true case _ => false} case _ => false}`, `AwQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE0V4Y2hhbmdlVHJhbnNhY3Rpb24EAAAAA2V0eAUAAAAHJG1hdGNoMAQAAAAHJG1hdGNoMQgICAUAAAADZXR4AAAACXNlbGxPcmRlcgAAAAlhc3NldFBhaXIAAAALYW1vdW50QXNzZXQEAAAACkJ5dGVWZWN0b3IFAAAAByRtYXRjaDEGB76y+jI=`, envWithExchangeTX, true, false}, - // - {`3P8M8XGF2uzDazV5fzdKNxrbC3YqCWScKxw`, ``, `AwoBAAAAGVJlbW92ZVVuZGVyc2NvcmVJZlByZXNlbnQAAAABAAAACXJlbWFpbmluZwMJAABmAAAAAgkAATEAAAABBQAAAAlyZW1haW5pbmcAAAAAAAAAAAAJAAEwAAAAAgUAAAAJcmVtYWluaW5nAAAAAAAAAAABBQAAAAlyZW1haW5pbmcKAQAAABJQYXJzZU5leHRBdHRyaWJ1dGUAAAABAAAACXJlbWFpbmluZwQAAAABcwkAATEAAAABBQAAAAlyZW1haW5pbmcDCQAAZgAAAAIFAAAAAXMAAAAAAAAAAAAEAAAAAm5uCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEJAAEvAAAAAgUAAAAJcmVtYWluaW5nAAAAAAAAAAACBAAAAAF2CQABLwAAAAIJAAEwAAAAAgUAAAAJcmVtYWluaW5nAAAAAAAAAAACBQAAAAJubgQAAAAMdG1wUmVtYWluaW5nCQABMAAAAAIFAAAACXJlbWFpbmluZwkAAGQAAAACBQAAAAJubgAAAAAAAAAAAgQAAAAOcmVtYWluaW5nU3RhdGUJAQAAABlSZW1vdmVVbmRlcnNjb3JlSWZQcmVzZW50AAAAAQUAAAAMdG1wUmVtYWluaW5nCQAETAAAAAIFAAAAAXYJAARMAAAAAgUAAAAOcmVtYWluaW5nU3RhdGUFAAAAA25pbAkAAAIAAAABAgAAADRFbXB0eSBzdHJpbmcgd2FzIHBhc3NlZCBpbnRvIHBhcnNlTmV4dEF0dHJpYnV0ZSBmdW5jCgEAAAATUGFyc2VHYW1lUmF3RGF0YVN0cgAAAAEAAAALcmF3U3RhdGVTdHIEAAAACWdhbWVTdGF0ZQkBAAAAElBhcnNlTmV4dEF0dHJpYnV0ZQAAAAEFAAAAC3Jhd1N0YXRlU3RyBAAAAAxwbGF5ZXJDaG9pY2UJAQAAABJQYXJzZU5leHRBdHRyaWJ1dGUAAAABCQABkQAAAAIFAAAACWdhbWVTdGF0ZQAAAAAAAAAAAQQAAAAOcGxheWVyUHViS2V5NTgJAQAAABJQYXJzZU5leHRBdHRyaWJ1dGUAAAABCQABkQAAAAIFAAAADHBsYXllckNob2ljZQAAAAAAAAAAAQQAAAANc3RhcnRlZEhlaWdodAkBAAAAElBhcnNlTmV4dEF0dHJpYnV0ZQAAAAEJAAGRAAAAAgUAAAAOcGxheWVyUHViS2V5NTgAAAAAAAAAAAEEAAAABndpbkFtdAkBAAAAElBhcnNlTmV4dEF0dHJpYnV0ZQAAAAEJAAGRAAAAAgUAAAANc3RhcnRlZEhlaWdodAAAAAAAAAAAAQkABEwAAAACCQABkQAAAAIFAAAACWdhbWVTdGF0ZQAAAAAAAAAAAAkABEwAAAACCQABkQAAAAIFAAAADHBsYXllckNob2ljZQAAAAAAAAAAAAkABEwAAAACCQABkQAAAAIFAAAADnBsYXllclB1YktleTU4AAAAAAAAAAAACQAETAAAAAIJAAGRAAAAAgUAAAANc3RhcnRlZEhlaWdodAAAAAAAAAAAAAkABEwAAAACCQABkQAAAAIFAAAABndpbkFtdAAAAAAAAAAAAAUAAAADbmlsCQAAAAAAAAIJAQAAABNQYXJzZUdhbWVSYXdEYXRhU3RyAAAAAQIAAABWMDNXT05fMDUzNTY0Ml80NDM4OXBhNmlOaHgxaEZEcU5abVNBVEp1ZldaMUVMbUtkOUh4eXpQUUtIdWMzXzA3MTYxMDU1N18wOTExNDAwMDAwMF8wMTYJAARMAAAAAgIAAAADV09OCQAETAAAAAICAAAABTM1NjQyCQAETAAAAAICAAAALDM4OXBhNmlOaHgxaEZEcU5abVNBVEp1ZldaMUVMbUtkOUh4eXpQUUtIdWMzCQAETAAAAAICAAAABzE2MTA1NTcJAARMAAAAAgIAAAAJMTE0MDAwMDAwBQAAAANuaWyuDQ4Y`, envWithExchangeTX, true, false}, - - //{"EQ", `5 == 5`, `AQkAAAAAAAACAAAAAAAAAAAFAAAAAAAAAAAFqWG0Fw==`, env, true, false}, - //{"ISINSTANCEOF", `match tx {case t : TransferTransaction => true case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB5yQ/+k=`, env, true, false}, - //{`THROW`, `true && throw("mess")`, `AQMGCQAAAgAAAAECAAAABG1lc3MH7PDwAQ==`, env, false, true}, - //{`SUM_LONG`, `1 + 1 > 0`, `AQkAAGYAAAACCQAAZAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEAAAAAAAAAAABiJjSk`, env, true, false}, - //{`SUB_LONG`, `2 - 1 > 0`, `AQkAAGYAAAACCQAAZQAAAAIAAAAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAABqsps1`, env, true, false}, - //{`GT_LONG`, `1 > 0`, `AQkAAGYAAAACAAAAAAAAAAABAAAAAAAAAAAAyAIM4w==`, env, true, false}, - //{`GE_LONG`, `1 >= 0`, `AQkAAGcAAAACAAAAAAAAAAABAAAAAAAAAAAAm30DnQ==`, env, true, false}, - //{`MUL_LONG`, `2 * 2>0`, `AQkAAGYAAAACCQAAaAAAAAIAAAAAAAAAAAIAAAAAAAAAAAIAAAAAAAAAAABCMM5o`, env, true, false}, - //{`DIV_LONG`, `4 / 2>0`, `AQkAAGYAAAACCQAAaQAAAAIAAAAAAAAAAAQAAAAAAAAAAAIAAAAAAAAAAAAadVma`, env, true, false}, - //{`DIV_LONG`, `10000 / (27+121) == 67`, `AwkAAAAAAAACCQAAaQAAAAIAAAAAAAAAJxAJAABkAAAAAgAAAAAAAAAAGwAAAAAAAAAAeQAAAAAAAAAAQ1vSVaQ=`, env, true, false}, - //{`DIV_LONG`, `((98750005 * (100 - 4)) / 100) == 94800004`, `AwkAAAAAAAACCQAAaQAAAAIJAABoAAAAAgAAAAAABeLONQkAAGUAAAACAAAAAAAAAABkAAAAAAAAAAAEAAAAAAAAAABkAAAAAAAFpoiEGMUZcA==`, env, true, false}, - //{`MOD_LONG`, `-10 % 6>0`, `AQkAAGYAAAACCQAAagAAAAIA//////////YAAAAAAAAAAAYAAAAAAAAAAAB5rBSH`, env, true, false}, - //{`MOD_LONG`, `10000 % 100 == 0`, `AwkAAAAAAAACCQAAagAAAAIAAAAAAAAAJxAAAAAAAAAAAGQAAAAAAAAAAAAmFt9K`, env, true, false}, - //{`FRACTION`, `fraction(10, 5, 2)>0`, `AQkAAGYAAAACCQAAawAAAAMAAAAAAAAAAAoAAAAAAAAAAAUAAAAAAAAAAAIAAAAAAAAAAACRyFu2`, env, true, false}, - //{`POW`, `pow(12, 1, 3456, 3, 2, Down()) == 187`, `AwkAAAAAAAACCQAAbAAAAAYAAAAAAAAAAAwAAAAAAAAAAAEAAAAAAAAADYAAAAAAAAAAAAMAAAAAAAAAAAIJAQAAAAREb3duAAAAAAAAAAAAAAAAu9llw2M=`, env, true, false}, - //{`POW`, `pow(12, 1, 3456, 3, 2, UP) == 188`, `AwkAAAAAAAACCQAAbAAAAAYAAAAAAAAAAAwAAAAAAAAAAAEAAAAAAAAADYAAAAAAAAAAAAMAAAAAAAAAAAIFAAAAAlVQAAAAAAAAAAC8evjDQQ==`, env, true, false}, - //{`POW`, `pow(12, 1, 3456, 3, 2, UP) == 187`, `AwkAAAAAAAACCQAAbAAAAAYAAAAAAAAAAAwAAAAAAAAAAAEAAAAAAAAADYAAAAAAAAAAAAMAAAAAAAAAAAIFAAAAAlVQAAAAAAAAAAC7FUMwCQ==`, env, false, false}, - //{`LOG`, `log(16, 0, 2, 0, 0, CEILING) == 4`, `AwkAAAAAAAACCQAAbQAAAAYAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAFAAAAB0NFSUxJTkcAAAAAAAAAAARh6Dy6`, env, true, false}, - //{`LOG`, `log(100, 0, 10, 0, 0, CEILING) == 2`, `AwkAAAAAAAACCQAAbQAAAAYAAAAAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAFAAAAB0NFSUxJTkcAAAAAAAAAAAJ7Op42`, env, true, false}, - // - //{`SIZE_BYTES`, `size(base58'abcd') > 0`, `AQkAAGYAAAACCQAAyAAAAAEBAAAAA2QGAgAAAAAAAAAAACMcdM4=`, env, true, false}, - //{`TAKE_BYTES`, `size(take(base58'abcd', 2)) == 2`, `AQkAAAAAAAACCQAAyAAAAAEJAADJAAAAAgEAAAADZAYCAAAAAAAAAAACAAAAAAAAAAACccrCZg==`, env, true, false}, - //{`DROP_BYTES`, `size(drop(base58'abcd', 2)) > 0`, `AQkAAGYAAAACCQAAyAAAAAEJAADKAAAAAgEAAAADZAYCAAAAAAAAAAACAAAAAAAAAAAA+srbUQ==`, env, true, false}, - {`DROP_BYTES`, `let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, env, true, false}, - //{`SUM_BYTES`, `size(base58'ab' + base58'cd') > 0`, `AQkAAGYAAAACCQAAyAAAAAEJAADLAAAAAgEAAAACB5wBAAAAAggSAAAAAAAAAAAAo+LRIA==`, env, true, false}, - // - //{`SUM_STRING`, `"ab"+"cd" == "abcd"`, `AQkAAAAAAAACCQABLAAAAAICAAAAAmFiAgAAAAJjZAIAAAAEYWJjZMBJvls=`, env, true, false}, - //{`TAKE_STRING`, `take("abcd", 2) == "ab"`, `AQkAAAAAAAACCQABLwAAAAICAAAABGFiY2QAAAAAAAAAAAICAAAAAmFiiXc+oQ==`, env, true, false}, - //{`TAKE_STRING`, `take("", 1) == ""`, `AwkAAAAAAAACCQABLwAAAAICAAAAAAAAAAAAAAAAAQIAAAAAmz5yjQ==`, env, true, false}, - //{`DROP_STRING`, `drop("abcd", 2) == "cd"`, `AQkAAAAAAAACCQABMAAAAAICAAAABGFiY2QAAAAAAAAAAAICAAAAAmNkZQdjWQ==`, env, true, false}, - //{`SIZE_STRING`, `size("abcd") == 4`, `AQkAAAAAAAACCQABMQAAAAECAAAABGFiY2QAAAAAAAAAAAScZzsq`, env, true, false}, - // - //{`SIZE_LIST`, `size(tx.proofs) == 8`, `AwkAAAAAAAACCQABkAAAAAEIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAgEd23x`, env, true, false}, - //{`GET_LIST`, `size(tx.proofs[0]) > 0`, `AQkAAGYAAAACCQAAyAAAAAEJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAAAAAAAAAAAAFF6iVo=`, env, true, false}, - //{`LONG_TO_BYTES`, `toBytes(1) == base58'11111112'`, `AQkAAAAAAAACCQABmgAAAAEAAAAAAAAAAAEBAAAACAAAAAAAAAABm8cc1g==`, env, true, false}, - //{`STRING_TO_BYTES`, `toBytes("привет") == base58'4wUjatAwfVDjaHQVX'`, `AQkAAAAAAAACCQABmwAAAAECAAAADNC/0YDQuNCy0LXRggEAAAAM0L/RgNC40LLQtdGCuUGFxw==`, env, true, false}, - //{`BOOLEAN_TO_BYTES`, `toBytes(true) == base58'2'`, `AQkAAAAAAAACCQABnAAAAAEGAQAAAAEBJRrQbw==`, env, true, false}, - //{`LONG_TO_STRING`, `toString(5) == "5"`, `AQkAAAAAAAACCQABpAAAAAEAAAAAAAAAAAUCAAAAATXPb5tR`, env, true, false}, - //{`BOOLEAN_TO_STRING`, `toString(true) == "true"`, `AQkAAAAAAAACCQABpQAAAAEGAgAAAAR0cnVlL6ZrWg==`, env, true, false}, - // - //{`SIGVERIFY`, `sigVerify(tx.bodyBytes, tx.proofs[0], base58'14ovLL9a6xbBfftyxGNLKMdbnzGgnaFQjmgUJGdho6nY')`, `AQkAAfQAAAADCAUAAAACdHgAAAAJYm9keUJ5dGVzCQABkQAAAAIIBQAAAAJ0eAAAAAZwcm9vZnMAAAAAAAAAAAABAAAAIAD5y2Wf7zxfv7l+9tcWxyLAbktd9nCbdvFMnxmREqV1igWi3A==`, env, true, false}, - //{`KECCAK256`, `keccak256(base58'a') != base58'a'`, `AQkBAAAAAiE9AAAAAgkAAfUAAAABAQAAAAEhAQAAAAEhKeR77g==`, env, true, false}, - //{`BLAKE256`, `blake2b256(base58'a') != base58'a'`, `AQkBAAAAAiE9AAAAAgkAAfYAAAABAQAAAAEhAQAAAAEh50D2WA==`, env, true, false}, - //{`SHA256`, `sha256(base58'a') != base58'a'`, `AQkBAAAAAiE9AAAAAgkAAfcAAAABAQAAAAEhAQAAAAEhVojmeg==`, env, true, false}, - //{`RSAVERIFY`, `let pk = fromBase64String("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkDg8m0bCDX7fTbBlHZm+BZIHVOfC2I4klRbjSqwFi/eCdfhGjYRYvu/frpSO0LIm0beKOUvwat6DY4dEhNt2PW3UeQvT2udRQ9VBcpwaJlLreCr837sn4fa9UG9FQFaGofSww1O9eBBjwMXeZr1jOzR9RBIwoL1TQkIkZGaDXRltEaMxtNnzotPfF3vGIZZuZX4CjiitHaSC0zlmQrEL3BDqqoLwo3jq8U3Zz8XUMyQElwufGRbZqdFCeiIs/EoHiJm8q8CVExRoxB0H/vE2uDFK/OXLGTgfwnDlrCa/qGt9Zsb8raUSz9IIHx72XB+kOXTt/GOuW7x2dJvTJIqKTwIDAQAB"); let msg = fromBase64String("REIiN2hDQUxIJVQzdk1zQSpXclRRelExVWd+YGQoOyx0KHduPzFmcU8zUWosWiA7aFloOWplclAxPCU="); let sig = fromBase64String("OXVKJwtSoenRmwizPtpjh3sCNmOpU1tnXUnyzl+PEI1P9Rx20GkxkIXlysFT2WdbPn/HsfGMwGJW7YhrVkDXy4uAQxUxSgQouvfZoqGSPp1NtM8iVJOGyKiepgB3GxRzQsev2G8Ik47eNkEDVQa47ct9j198Wvnkf88yjSkK0KxR057MWAi20ipNLirW4ZHDAf1giv68mniKfKxsPWahOA/7JYkv18sxcsISQqRXM8nGI1UuSLt9ER7kIzyAk2mgPCiVlj0hoPGUytmbiUqvEM4QaJfCpR0wVO4f/fob6jwKkGT6wbtia+5xCD7bESIHH8ISDrdexZ01QyNP2r4enw=="); rsaVerify(SHA3256, msg, sig, pk)`, `AwQAAAACcGsJAAJbAAAAAQIAAAGITUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFrRGc4bTBiQ0RYN2ZUYkJsSFptK0JaSUhWT2ZDMkk0a2xSYmpTcXdGaS9lQ2RmaEdqWVJZdnUvZnJwU08wTEltMGJlS09VdndhdDZEWTRkRWhOdDJQVzNVZVF2VDJ1ZFJROVZCY3B3YUpsTHJlQ3I4MzdzbjRmYTlVRzlGUUZhR29mU3d3MU85ZUJCandNWGVacjFqT3pSOVJCSXdvTDFUUWtJa1pHYURYUmx0RWFNeHRObnpvdFBmRjN2R0laWnVaWDRDamlpdEhhU0MwemxtUXJFTDNCRHFxb0x3bzNqcThVM1p6OFhVTXlRRWx3dWZHUmJacWRGQ2VpSXMvRW9IaUptOHE4Q1ZFeFJveEIwSC92RTJ1REZLL09YTEdUZ2Z3bkRsckNhL3FHdDlac2I4cmFVU3o5SUlIeDcyWEIra09YVHQvR091Vzd4MmRKdlRKSXFLVHdJREFRQUIEAAAAA21zZwkAAlsAAAABAgAAAFBSRUlpTjJoRFFVeElKVlF6ZGsxelFTcFhjbFJSZWxFeFZXZCtZR1FvT3l4MEtIZHVQekZtY1U4elVXb3NXaUE3YUZsb09XcGxjbEF4UENVPQQAAAADc2lnCQACWwAAAAECAAABWE9YVktKd3RTb2VuUm13aXpQdHBqaDNzQ05tT3BVMXRuWFVueXpsK1BFSTFQOVJ4MjBHa3hrSVhseXNGVDJXZGJQbi9Ic2ZHTXdHSlc3WWhyVmtEWHk0dUFReFV4U2dRb3V2ZlpvcUdTUHAxTnRNOGlWSk9HeUtpZXBnQjNHeFJ6UXNldjJHOElrNDdlTmtFRFZRYTQ3Y3Q5ajE5OFd2bmtmODh5alNrSzBLeFIwNTdNV0FpMjBpcE5MaXJXNFpIREFmMWdpdjY4bW5pS2ZLeHNQV2FoT0EvN0pZa3YxOHN4Y3NJU1FxUlhNOG5HSTFVdVNMdDlFUjdrSXp5QWsybWdQQ2lWbGowaG9QR1V5dG1iaVVxdkVNNFFhSmZDcFIwd1ZPNGYvZm9iNmp3S2tHVDZ3YnRpYSs1eENEN2JFU0lISDhJU0RyZGV4WjAxUXlOUDJyNGVudz09CQAB+AAAAAQFAAAAB1NIQTMyNTYFAAAAA21zZwUAAAADc2lnBQAAAAJwa8wcz28=`, env, true, false}, - // - //{`TOBASE58`, `toBase58String(base58'a') == "a"`, `AQkAAAAAAAACCQACWAAAAAEBAAAAASECAAAAAWFcT4nY`, env, true, false}, - //{`FROMBASE58`, `fromBase58String("a") == base58'a'`, `AQkAAAAAAAACCQACWQAAAAECAAAAAWEBAAAAASEB1Qmd`, env, true, false}, - //{`FROMBASE58`, `fromBase58String(extract("")) == base58''`, `AwkAAAAAAAACCQACWQAAAAEJAQAAAAdleHRyYWN0AAAAAQIAAAAAAQAAAAAt2xTN`, env, true, false}, - //{`TOBASE64`, `toBase64String(base16'544553547465737454455354') == "VEVTVHRlc3RURVNU"`, `AwkAAAAAAAACCQACWgAAAAEBAAAADFRFU1R0ZXN0VEVTVAIAAAAQVkVWVFZIUmxjM1JVUlZOVd6DVfc=`, env, true, false}, - //{`FROMBASE64`, `base16'544553547465737454455354' == fromBase64String("VEVTVHRlc3RURVNU")`, `AwkAAAAAAAACAQAAAAxURVNUdGVzdFRFU1QJAAJbAAAAAQIAAAAQVkVWVFZIUmxjM1JVUlZOVV+c29Q=`, env, true, false}, - //{`TOBASE16`, `toBase16String(base64'VEVTVHRlc3RURVNU') == "544553547465737454455354"`, `AwkAAAAAAAACCQACXAAAAAEBAAAADFRFU1R0ZXN0VEVTVAIAAAAYNTQ0NTUzNTQ3NDY1NzM3NDU0NDU1MzU07NMrMQ==`, env, true, false}, - //{`FROMBASE16`, `fromBase16String("544553547465737454455354") == base64'VEVTVHRlc3RURVNU'`, `AwkAAAAAAAACCQACXQAAAAECAAAAGDU0NDU1MzU0NzQ2NTczNzQ1NDQ1NTM1NAEAAAAMVEVTVHRlc3RURVNUFBEa5A==`, env, true, false}, - // - //{`CHECKMERKLEPROOF`, `let rootHash = base64'eh9fm3HeHZ3XA/UfMpC9HSwLVMyBLgkAJL0MIVBIoYk='; let leafData = base64'AAAm+w=='; let merkleProof = base64'ACBSs2di6rY+9N3mrpQVRNZLGAdRX2WBD6XkrOXuhh42XwEgKhB3Aiij6jqLRuQhrwqv6e05kr89tyxkuFYwUuMCQB8AIKLhp/AFQkokTe/NMQnKFL5eTMvDlFejApmJxPY6Rp8XACAWrdgB8DwvPA8D04E9HgUjhKghAn5aqtZnuKcmpLHztQAgd2OG15WYz90r1WipgXwjdq9WhvMIAtvGlm6E3WYY12oAIJXPPVIdbwOTdUJvCgMI4iape2gvR55vsrO2OmJJtZUNASAya23YyBl+EpKytL9+7cPdkeMMWSjk0Bc0GNnqIisofQ=='; checkMerkleProof(rootHash, merkleProof, leafData)`, `AwQAAAAIcm9vdEhhc2gBAAAAIHofX5tx3h2d1wP1HzKQvR0sC1TMgS4JACS9DCFQSKGJBAAAAAhsZWFmRGF0YQEAAAAEAAAm+wQAAAALbWVya2xlUHJvb2YBAAAA7gAgUrNnYuq2PvTd5q6UFUTWSxgHUV9lgQ+l5Kzl7oYeNl8BICoQdwIoo+o6i0bkIa8Kr+ntOZK/PbcsZLhWMFLjAkAfACCi4afwBUJKJE3vzTEJyhS+XkzLw5RXowKZicT2OkafFwAgFq3YAfA8LzwPA9OBPR4FI4SoIQJ+WqrWZ7inJqSx87UAIHdjhteVmM/dK9VoqYF8I3avVobzCALbxpZuhN1mGNdqACCVzz1SHW8Dk3VCbwoDCOImqXtoL0eeb7KztjpiSbWVDQEgMmtt2MgZfhKSsrS/fu3D3ZHjDFko5NAXNBjZ6iIrKH0JAAK8AAAAAwUAAAAIcm9vdEhhc2gFAAAAC21lcmtsZVByb29mBQAAAAhsZWFmRGF0YXe8Icg=`, env, true, false}, - // - //{`GETTRANSACTIONBYID`, `V2: match transactionById(tx.id) {case _: TransferTransaction => true; case _ => false}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24GB9Sc8FA=`, env, true, false}, - //{`TRANSACTIONHEIGHTBYID`, `transactionHeightById(base58'aaaa') == 5`, `AQkAAAAAAAACCQAD6QAAAAEBAAAAA2P4ZwAAAAAAAAAABSLhRM4=`, env, false, false}, - //{`ACCOUNTASSETBALANCE`, `assetBalance(tx.sender, base58'BXBUNddxTGTQc3G4qHYn5E67SBwMj18zLncUr871iuRD') == 5`, `AQkAAAAAAAACCQAD6wAAAAIIBQAAAAJ0eAAAAAZzZW5kZXIBAAAAIJxQIls8iGUc1935JolBz6bYc37eoPDtScOAM0lTNhY0AAAAAAAAAAAFjp6PBg==`, env, true, false}, - //{`ADDRESSTOSTRING`, `toString(Address(base58'3P3336rNSSU8bDAqDb6S5jNs8DJb2bfNmpg')) == "3P3336rNSSU8bDAqDb6S5jNs8DJb2bfNmpg"`, `AwkAAAAAAAACCQAEJQAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVcMIZxOsk2Gw5Avd0ztqi+phtb1Bb83MiUCAAAAIzNQMzMzNnJOU1NVOGJEQXFEYjZTNWpOczhESmIyYmZObXBnkXj7Cg==`, env, true, false}, - //{`ADDRESSTOSTRING`, `toString(Address(base58'3P3336rNSSU8bDAqDb6S5jNs8DJb2bfNmpg')) == "3P3336rNSSU8bDAqDb6S5jNs8DJb2bfNmpf"`, `AwkAAAAAAAACCQAEJQAAAAEJAQAAAAdBZGRyZXNzAAAAAQEAAAAaAVcMIZxOsk2Gw5Avd0ztqi+phtb1Bb83MiUCAAAAIzNQMzMzNnJOU1NVOGJEQXFEYjZTNWpOczhESmIyYmZObXBmb/6mcg==`, env, false, false}, - //{`CONS`, `size([1, "2"]) == 2`, `AwkAAAAAAAACCQABkAAAAAEJAARMAAAAAgAAAAAAAAAAAQkABEwAAAACAgAAAAEyBQAAAANuaWwAAAAAAAAAAAKuUcc0`, env, true, false}, - //{`CONS`, `size(cons(1, nil)) == 1`, `AwkAAAAAAAACCQABkAAAAAEJAARMAAAAAgAAAAAAAAAAAQUAAAADbmlsAAAAAAAAAAABX96esw==`, env, true, false}, - //{`CONS`, `[1, 2, 3, 4, 5][4] == 5`, `AwkAAAAAAAACCQABkQAAAAIJAARMAAAAAgAAAAAAAAAAAQkABEwAAAACAAAAAAAAAAACCQAETAAAAAIAAAAAAAAAAAMJAARMAAAAAgAAAAAAAAAABAkABEwAAAACAAAAAAAAAAAFBQAAAANuaWwAAAAAAAAAAAQAAAAAAAAAAAVrPjYC`, env, true, false}, - //{`CONS`, `[1, 2, 3, 4, 5][4] == 4`, `AwkAAAAAAAACCQABkQAAAAIJAARMAAAAAgAAAAAAAAAAAQkABEwAAAACAAAAAAAAAAACCQAETAAAAAIAAAAAAAAAAAMJAARMAAAAAgAAAAAAAAAABAkABEwAAAACAAAAAAAAAAAFBQAAAANuaWwAAAAAAAAAAAQAAAAAAAAAAASbi8eN`, env, false, false}, - //{`UTF8STR`, `toUtf8String(base16'536f6d65207465737420737472696e67') == "Some test string"`, `AwkAAAAAAAACCQAEsAAAAAEBAAAAEFNvbWUgdGVzdCBzdHJpbmcCAAAAEFNvbWUgdGVzdCBzdHJpbme0Wj5y`, env, true, false}, - //{`UTF8STR`, `toUtf8String(base16'536f6d65207465737420737472696e67') == "blah-blah-blah"`, `AwkAAAAAAAACCQAEsAAAAAEBAAAAEFNvbWUgdGVzdCBzdHJpbmcCAAAADmJsYWgtYmxhaC1ibGFojpjG3g==`, env, false, false}, - //{`TOINT`, `toInt(base16'0000000000003039') == 12345`, `AwkAAAAAAAACCQAEsQAAAAEBAAAACAAAAAAAADA5AAAAAAAAADA5WVzTeQ==`, env, true, false}, - //{`TOINT`, `toInt(base16'3930000000000000') == 12345`, `AwkAAAAAAAACCQAEsQAAAAEBAAAACDkwAAAAAAAAAAAAAAAAADA5Vq02Hg==`, env, false, false}, - //{`TOINT_OFF`, `toInt(base16'ffffff0000000000003039', 3) == 12345`, `AwkAAAAAAAACCQAEsgAAAAIBAAAAC////wAAAAAAADA5AAAAAAAAAAADAAAAAAAAADA5pGJt2g==`, env, true, false}, - //{`TOINT_OFF`, `toInt(base16'ffffff0000000000003039', 2) == 12345`, `AwkAAAAAAAACCQAEsgAAAAIBAAAAC////wAAAAAAADA5AAAAAAAAAAACAAAAAAAAADA57UQA4Q==`, env, false, false}, - //{`INDEXOF`, `indexOf("cafe bebe dead beef cafe bebe", "bebe") == 5`, `AwkAAAAAAAACCQAEswAAAAICAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARiZWJlAAAAAAAAAAAFyqpjwQ==`, env, true, false}, - //{`INDEXOF`, `indexOf("cafe bebe dead beef cafe bebe", "fox") == unit`, `AwkAAAAAAAACCQAEswAAAAICAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAANmb3gFAAAABHVuaXS7twzl`, env, true, false}, - //{`INDEXOF`, `indexOf("世界}}世界", "}}") == 2`, `AwkAAAAAAAACCQAEswAAAAICAAAADuS4lueVjH195LiW55WMAgAAAAJ9fQAAAAAAAAAAAjCgf3g=`, env, true, false}, - //{`INDEXOFN`, `indexOf("cafe bebe dead beef cafe bebe", "bebe", 0) == 5`, `AwkAAAAAAAACCQAEtAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARiZWJlAAAAAAAAAAAAAAAAAAAAAAAFFBPTAA==`, env, true, false}, - //{`INDEXOFN`, `indexOf("cafe bebe dead beef cafe bebe", "bebe", 10) == 25`, `AwkAAAAAAAACCQAEtAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARiZWJlAAAAAAAAAAAKAAAAAAAAAAAZVBpWMw==`, env, true, false}, - //{`INDEXOFN`, `indexOf("cafe bebe dead beef cafe bebe", "dead", 10) == 10`, `AwkAAAAAAAACCQAEtAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARkZWFkAAAAAAAAAAAKAAAAAAAAAAAKstuWEQ==`, env, true, false}, - //{`INDEXOFN`, `indexOf("cafe bebe dead beef cafe bebe", "dead", 11) == unit`, `AwkAAAAAAAACCQAEtAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARkZWFkAAAAAAAAAAALBQAAAAR1bml0f2q2UQ==`, env, true, false}, - //{`SPLIT`, `split("abcd", "") == ["a", "b", "c", "d"]`, `AwkAAAAAAAACCQAEtQAAAAICAAAABGFiY2QCAAAAAAkABEwAAAACAgAAAAFhCQAETAAAAAICAAAAAWIJAARMAAAAAgIAAAABYwkABEwAAAACAgAAAAFkBQAAAANuaWwrnSMu`, env, true, false}, - //{`SPLIT`, `split("one two three", " ") == ["one", "two", "three"]`, `AwkAAAAAAAACCQAEtQAAAAICAAAADW9uZSB0d28gdGhyZWUCAAAAASAJAARMAAAAAgIAAAADb25lCQAETAAAAAICAAAAA3R3bwkABEwAAAACAgAAAAV0aHJlZQUAAAADbmlsdBcUog==`, env, true, false}, - //{`PARSEINT`, `parseInt("12345") == 12345`, `AwkAAAAAAAACCQAEtgAAAAECAAAABTEyMzQ1AAAAAAAAADA57cmovA==`, env, true, false}, - //{`PARSEINT`, `parseInt("0x12345") == unit`, `AwkAAAAAAAACCQAEtgAAAAECAAAABzB4MTIzNDUFAAAABHVuaXQvncQM`, env, true, false}, - //{`LASTINDEXOF`, `lastIndexOf("cafe bebe dead beef cafe bebe", "bebe") == 25`, `AwkAAAAAAAACCQAEtwAAAAICAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARiZWJlAAAAAAAAAAAZDUvNng==`, env, true, false}, - //{`LASTINDEXOF`, `lastIndexOf("cafe bebe dead beef cafe bebe", "fox") == unit`, `AwkAAAAAAAACCQAEtwAAAAICAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAANmb3gFAAAABHVuaXSK8YYp`, env, true, false}, - //{`LASTINDEXOFN`, `lastIndexOf("cafe bebe dead beef cafe bebe", "bebe", 30) == 25`, `AwkAAAAAAAACCQAEuAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARiZWJlAAAAAAAAAAAeAAAAAAAAAAAZus4/9A==`, env, true, false}, - //{`LASTINDEXOFN`, `lastIndexOf("cafe bebe dead beef cafe bebe", "bebe", 10) == 5`, `AwkAAAAAAAACCQAEuAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARiZWJlAAAAAAAAAAAKAAAAAAAAAAAFrGUCxA==`, env, true, false}, - //{`LASTINDEXOFN`, `lastIndexOf("cafe bebe dead beef cafe bebe", "dead", 13) == 10`, `AwkAAAAAAAACCQAEuAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARkZWFkAAAAAAAAAAANAAAAAAAAAAAKepNV2A==`, env, true, false}, - //{`LASTINDEXOFN`, `lastIndexOf("cafe bebe dead beef cafe bebe", "dead", 11) == 10`, `AwkAAAAAAAACCQAEuAAAAAMCAAAAHWNhZmUgYmViZSBkZWFkIGJlZWYgY2FmZSBiZWJlAgAAAARkZWFkAAAAAAAAAAALAAAAAAAAAAAKcxKwfA==`, env, true, false}, - } { - src, err := base64.StdEncoding.DecodeString(test.script) - require.NoError(t, err, test.name) - - tree, err := Parse(src) - require.NoError(t, err, test.name) - assert.NotNil(t, tree, test.name) - - script, err := Compile(tree) - require.NoError(t, err, test.name) - assert.NotNil(t, script, test.name) - - res, err := script.Run(test.env) - if test.error { - assert.Error(t, err, "No error in "+test.name) - } else { - require.NoError(t, err, "Unexpected error in: "+test.name) - assert.NotNil(t, res, test.name) - r, ok := res.(ScriptResult) - assert.True(t, ok, test.name) - assert.Equal(t, test.result, r.Result(), test.name) - } - } -} - -func BenchmarkSimplestScript(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - src, err := base64.StdEncoding.DecodeString("AwZd0cYf") // V3: true - require.NoError(b, err) - tree, err := Parse(src) - require.NoError(b, err) - prg, err := Compile(tree) - require.NoError(b, err) - assert.NotNil(b, prg) - res, err := prg.Run(nil) - require.NoError(b, err) - r := res.(ScriptResult) - assert.True(b, r.Result()) - } -} - -func BenchmarkEval(b *testing.B) { - //let x = addressFromString("3PJaDyprvekvPXPuAtxrapacuDJopgJRaU3") - // - //let a = x - //let b = a - //let c = b - //let d = c - //let e = d - //let f = e - // - //f == e - - code := "AQQAAAABeAkBAAAAEWFkZHJlc3NGcm9tU3RyaW5nAAAAAQIAAAAjM1BKYUR5cHJ2ZWt2UFhQdUF0eHJhcGFjdURKb3BnSlJhVTMEAAAAAWEFAAAAAXgEAAAAAWIFAAAAAWEEAAAAAWMFAAAAAWIEAAAAAWQFAAAAAWMEAAAAAWUFAAAAAWQEAAAAAWYFAAAAAWUJAAAAAAAAAgUAAAABZgUAAAABZS5FHzs=" - b.ReportAllocs() - src, err := base64.StdEncoding.DecodeString(code) - require.NoError(b, err) - tree, err := Parse(src) - require.NoError(b, err) - prg, err := Compile(tree) - require.NoError(b, err) - assert.NotNil(b, prg) - b.ResetTimer() - for i := 0; i < b.N; i++ { - res, err := prg.Run(nil) //TODO: pass real value - require.NoError(b, err) - r := res.(ScriptResult) - assert.True(b, r.Result()) - } -} - func testTransferWithProofs() *proto.TransferWithProofs { var scheme byte = 'T' seed, err := base58.Decode("3TUPTbbpiM5UmZDhMmzdsKKNgMvyHwZQncKWfJrxk3bc") From 5d035b34b611135801606b098119a65d95add1fa Mon Sep 17 00:00:00 2001 From: frozen Date: Thu, 18 Mar 2021 18:04:13 +0300 Subject: [PATCH 43/55] Remove unused code. --- pkg/ride/compiler_helpers.go | 33 +--------- pkg/ride/environment.go | 12 ---- pkg/ride/functions_predefined.go | 13 ---- pkg/ride/program.go | 105 ------------------------------- pkg/ride/serializer.go | 1 - pkg/ride/tree_expand.go | 2 +- 6 files changed, 2 insertions(+), 164 deletions(-) delete mode 100644 pkg/ride/program.go diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index a6cbb2e78a..b144f16434 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -89,11 +89,6 @@ func (b *builder) ret() { b.w.WriteByte(OpReturn) } -func (b *builder) ref(uint162 uint16) { - b.w.WriteByte(OpRef) - b.w.Write(encode(uint162)) -} - func (b *builder) patch(at uint16, val []byte) { bts := b.w.Bytes()[at:] copy(bts, val) @@ -115,10 +110,6 @@ func (b *builder) call(id uint16, argc uint16) { b.w.Write(encode(id)) } -//func (b *builder) startPos() { -// b.startAt = uint16(b.w.Len()) -//} - func (b *builder) build() (map[string]Entrypoint, []byte) { return b.entrypoints, b.w.Bytes() } @@ -157,7 +148,7 @@ func (a point) Serialize(s Serializer) error { } s.Uint16(a.fn) - s.String(a.debugInfo) + _ = s.String(a.debugInfo) return nil } @@ -206,11 +197,6 @@ func (a *cell) set(u uniqueid, result rideType, fn uint16, position uint16, cons } } -func (a *cell) get(u uniqueid) (point, bool) { - rs, ok := a.values[u] - return rs, ok -} - type uniqueid = uint16 type refKind struct { @@ -230,16 +216,6 @@ func newReferences(prev *references) *references { } } -//func (a *references) get(name string) (uniqueid, bool) { -// if a == nil { -// return 0, false -// } -// if offset, ok := a.refs[name]; ok { -// return offset, ok -// } -// return a.prev.get(name) -//} - func (a *references) setAssigment(name string, uniq uniqueid) { a.refs[name] = append([]refKind{refKind{assigment: true, n: uniq}}, a.refs[name]...) } @@ -271,13 +247,6 @@ func (a *references) get(name string, assigment bool) (uniqueid, bool) { return a.prev.get(name, assigment) } -func (a *references) pop() *references { - if a.prev != nil { - return a.prev - } - panic("no previous refs") -} - type predefFunc struct { name string f rideFunction diff --git a/pkg/ride/environment.go b/pkg/ride/environment.go index b4b1c98f8b..f96da2847f 100644 --- a/pkg/ride/environment.go +++ b/pkg/ride/environment.go @@ -150,15 +150,3 @@ func (e *Environment) checkMessageLength(l int) bool { func (e *Environment) invocation() rideObject { return e.inv } - -func (e *Environment) functions(libVersion int) (Functions, error) { - functions, err := selectFunctions(libVersion) - if err != nil { - return nil, err - } - provider, err := selectFunctionNameProvider(libVersion) - if err != nil { - return nil, err - } - return functionsImpl{f: functions, p: provider}, nil -} diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index 92e95bd33a..d4996f5780 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -68,16 +68,3 @@ type Functions interface { function(int) rideFunction name(int) string } - -type functionsImpl struct { - f func(id int) rideFunction - p func(int) string -} - -func (a functionsImpl) function(v int) rideFunction { - return a.f(v) -} - -func (a functionsImpl) name(v int) string { - return a.p(v) -} diff --git a/pkg/ride/program.go b/pkg/ride/program.go deleted file mode 100644 index 0db856366a..0000000000 --- a/pkg/ride/program.go +++ /dev/null @@ -1,105 +0,0 @@ -package ride - -type callable struct { - entryPoint int - parameterName string -} - -type RideScript interface { - Run(env RideEnvironment) (RideResult, error) - code() []byte -} - -type SimpleScript struct { - LibVersion int - EntryPoint int - Code []byte - Constants []rideType -} - -func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { - panic("implement me") -} - -/* -func (s *SimpleScript) Run(env RideEnvironment) (RideResult, error) { - fs, err := selectFunctions(s.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "simple script execution failed") - } - gcs, err := selectConstants(s.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "simple script execution failed") - } - np, err := selectFunctionNameProvider(s.LibVersion) - if err != nil { - return nil, errors.Wrap(err, "simple script execution failed") - } - m := vm{ - env: env, - code: s.Code, - ip: 0, - constants: s.Constants, - functions: fs, - globals: gcs, - stack: make([]rideType, 0, 2), - //calls: make([]frame, 0, 2), - functionName: np, - } - r, err := m.run() - if err != nil { - return nil, errors.Wrap(err, "simple script execution failed") - } - return r, nil -} -*/ - -func (s *SimpleScript) code() []byte { - return s.Code -} - -type DAppScript struct { - LibVersion int - Code []byte - Constants []rideType - EntryPoints map[string]callable -} - -func (s *DAppScript) Run(env RideEnvironment) (RideResult, error) { - panic("DAppScript") - //if _, ok := s.EntryPoints[""]; !ok { - // return nil, errors.Errorf("no verifier") - //} - //fs, err := selectFunctions(s.LibVersion) - //if err != nil { - // return nil, errors.Wrap(err, "script execution failed") - //} - //gcs, err := selectConstants(s.LibVersion) - //if err != nil { - // return nil, errors.Wrap(err, "script execution failed") - //} - //np, err := selectFunctionNameProvider(s.LibVersion) - //if err != nil { - // return nil, errors.Wrap(err, "script execution failed") - //} - //m := vm{ - // env: env, - // code: s.Code, - // ip: 0, - // constants: s.Constants, - // functions: fs, - // globals: gcs, - // stack: make([]rideType, 0, 2), - // //calls: make([]frame, 0, 2), - // functionName: np, - //} - //r, err := m.run() - //if err != nil { - // return nil, errors.Wrap(err, "script execution failed") - //} - //return r, nil -} - -func (s *DAppScript) code() []byte { - return s.Code -} diff --git a/pkg/ride/serializer.go b/pkg/ride/serializer.go index 2ee50280e4..d3b0042eef 100644 --- a/pkg/ride/serializer.go +++ b/pkg/ride/serializer.go @@ -12,7 +12,6 @@ const ( sTrue byte = 101 sFalse byte = 102 sInt byte = 103 - sUint16 byte = 104 sBytes byte = 105 sString byte = 106 sPoint byte = 107 diff --git a/pkg/ride/tree_expand.go b/pkg/ride/tree_expand.go index 542c29486b..033add4f8e 100644 --- a/pkg/ride/tree_expand.go +++ b/pkg/ride/tree_expand.go @@ -65,7 +65,7 @@ func Expand(t *Tree) (*Tree, error) { scope = scope.add(v.Name, v2) functions = append(functions, v2) } - verifier := t.Verifier + var verifier Node if t.IsDApp() && t.HasVerifier() { verifier = cloneFuncDecl(t.Verifier.(*FunctionDeclarationNode), expand(scope, t.Verifier.(*FunctionDeclarationNode).Body), nil) } else { From 8b64449c67eb25ba6ffcdd39e525c285d0753687 Mon Sep 17 00:00:00 2001 From: frozen Date: Thu, 18 Mar 2021 18:15:04 +0300 Subject: [PATCH 44/55] Fix vetcheck errors. --- pkg/ride/compiler_helpers.go | 22 ---------------------- pkg/ride/decompiler.go | 2 +- pkg/ride/executable.go | 3 ++- pkg/ride/result.go | 11 +++++------ pkg/ride/tree.go | 14 ++++++++++---- 5 files changed, 18 insertions(+), 34 deletions(-) diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index b144f16434..0fca665db9 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -60,11 +60,6 @@ func (b *builder) writeStub(len int) (position uint16) { return position } -func (b *builder) push(uint162 uint16) { - b.w.WriteByte(OpRef) - b.w.Write(encode(uint162)) -} - func (b *builder) setStart(name string, argn int) { b.entrypoints[name] = Entrypoint{ name: name, @@ -104,12 +99,6 @@ func (b *builder) externalCall(id uint16, argc uint16) { b.w.Write(encode(argc)) } -// Call user defined function. -func (b *builder) call(id uint16, argc uint16) { - b.w.WriteByte(OpCall) - b.w.Write(encode(id)) -} - func (b *builder) build() (map[string]Entrypoint, []byte) { return b.entrypoints, b.w.Bytes() } @@ -278,17 +267,6 @@ func (a *predef) set(name string, id uint16, f rideFunction) { } } -func (a *predef) get(name string) (pfunc, bool) { - if a == nil { - return pfunc{}, false - } - rs, ok := a.m[name] - if ok { - return rs, ok - } - return a.prev.get(name) -} - func (a *predef) getn(id int) rideFunction { if a == nil { return nil diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index 49462a621f..4bd8aef15e 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -172,7 +172,7 @@ func detree(s *strings.Builder, tree Node) { s.WriteString(" }; ") detree(s, n.Block) case *ConditionalNode: - s.WriteString(fmt.Sprintf("if (")) + s.WriteString("if (") detree(s, n.Condition) s.WriteString(") { ") detree(s, n.TrueExpression) diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index 6a9f5e9ed9..e8be8f7e76 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -137,7 +137,8 @@ func (a *Executable) makeVm(environment RideEnvironment, entrypoint int, argumen } func (a *Executable) Serialize(s Serializer) error { - s.Byte(202) + var magicNumber byte = 202 + s.Byte(magicNumber) s.Uint16(uint16(a.LibVersion)) s.Bool(a.IsDapp) s.Bool(a.hasVerifier) diff --git a/pkg/ride/result.go b/pkg/ride/result.go index 52ccc82d56..c224f20bee 100644 --- a/pkg/ride/result.go +++ b/pkg/ride/result.go @@ -51,12 +51,11 @@ func (r ScriptResult) Eq(other RideResult) bool { } type DAppResult struct { - res bool // true - success, false - call failed, read msg - actions proto.ScriptActions - msg string - operations int - calls []callLog - refs Refs + res bool // true - success, false - call failed, read msg + actions proto.ScriptActions + msg string + calls []callLog + refs Refs } func (r DAppResult) Result() bool { diff --git a/pkg/ride/tree.go b/pkg/ride/tree.go index fd599be79d..18ab844e23 100644 --- a/pkg/ride/tree.go +++ b/pkg/ride/tree.go @@ -15,7 +15,9 @@ func (*LongNode) node() {} func (*LongNode) SetBlock(Node) {} func (a *LongNode) Clone() Node { - return &*a + return &LongNode{ + Value: a.Value, + } } func NewLongNode(v int64) *LongNode { @@ -31,8 +33,10 @@ func (*BytesNode) node() {} func (*BytesNode) SetBlock(Node) {} func (a *BytesNode) Clone() Node { - // Bytes references to the same location, but it makes no sense to modify them. - return &*a + return &BytesNode{ + // Bytes references to the same location. + Value: a.Value, + } } func NewBytesNode(v []byte) *BytesNode { @@ -48,7 +52,9 @@ func (*StringNode) node() {} func (*StringNode) SetBlock(Node) {} func (a *StringNode) Clone() Node { - return &*a + return &StringNode{ + Value: a.Value, + } } func NewStringNode(v string) *StringNode { From 366b203696a3851c75f81eb7e6be5ab2c9466a22 Mon Sep 17 00:00:00 2001 From: frozen Date: Thu, 18 Mar 2021 18:21:27 +0300 Subject: [PATCH 45/55] Fix vetcheck errors. --- pkg/ride/executable.go | 1 - pkg/ride/tree.go | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/ride/executable.go b/pkg/ride/executable.go index e8be8f7e76..ff684b5c58 100644 --- a/pkg/ride/executable.go +++ b/pkg/ride/executable.go @@ -10,7 +10,6 @@ type Executable struct { IsDapp bool hasVerifier bool position int // Non-default value assumes interrupted evaluation. - stack []rideType ByteCode []byte EntryPoints map[string]Entrypoint References map[uniqueid]point diff --git a/pkg/ride/tree.go b/pkg/ride/tree.go index 18ab844e23..da818d0afc 100644 --- a/pkg/ride/tree.go +++ b/pkg/ride/tree.go @@ -70,7 +70,9 @@ func (*BooleanNode) node() {} func (*BooleanNode) SetBlock(Node) {} func (a *BooleanNode) Clone() Node { - return &*a + return &BooleanNode{ + Value: a.Value, + } } func NewBooleanNode(v bool) *BooleanNode { From ba560d8cffe470ea43bb0935bcb240b39d6c3bef Mon Sep 17 00:00:00 2001 From: frozen Date: Thu, 18 Mar 2021 18:49:19 +0300 Subject: [PATCH 46/55] Set up go 1.16 --- .github/workflows/go.yml | 4 ++-- go.mod | 2 +- go.sum | 2 -- pkg/ride/compiler_helpers.go | 5 ----- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index e2a5d2f0a1..0059fb55bf 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -9,10 +9,10 @@ jobs: steps: - uses: actions/checkout@master - - name: Set up Go 1.15 + - name: Set up Go 1.16 uses: actions/setup-go@v1 with: - go-version: 1.15 + go-version: 1.16 id: go - name: Set up GolangCI-Lint diff --git a/go.mod b/go.mod index 3786ac545d..7fde6aa330 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/wavesplatform/gowaves -go 1.15 +go 1.16 require ( github.com/OneOfOne/xxhash v1.2.5 // indirect diff --git a/go.sum b/go.sum index bc0714993d..dfcce0cb5e 100644 --- a/go.sum +++ b/go.sum @@ -81,8 +81,6 @@ github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942/go.mod h1:ZW github.com/ethereum/go-ethereum v1.9.15/go.mod h1:slT8bPPRhXsyNTwHQxrOnjuTZ1sDXRajW11EkJ84QJ0= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4 h1:QJdN7XRRAp+ZEGl0ha5rjuL5/XJrEMtht0csVoVcvHA= -github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= 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= diff --git a/pkg/ride/compiler_helpers.go b/pkg/ride/compiler_helpers.go index 0fca665db9..3c2820612d 100644 --- a/pkg/ride/compiler_helpers.go +++ b/pkg/ride/compiler_helpers.go @@ -296,11 +296,6 @@ func (a constantDeferred) Write(p params, _ []byte) { func (a constantDeferred) Clean() { } -// -//func (a constantDeferred) N() uniqueid { -// return a.n -//} - func NewConstantDeferred(n uniqueid) constantDeferred { return constantDeferred{n: n} } From b50a0c774fb9bc245e443b61808defa5d00cea9e Mon Sep 17 00:00:00 2001 From: Frozen Date: Fri, 19 Mar 2021 11:56:03 +0300 Subject: [PATCH 47/55] Rewrite path. --- go.mod | 2 +- go.sum | 2 + pkg/ride/compiler2_test.go | 113 +++++++++++++++++++++++++++++ pkg/ride/compiler_state.go | 2 +- pkg/ride/decompiler.go | 3 + pkg/ride/tree_evaluation.go | 24 ++++--- pkg/ride/tree_evaluation_test.go | 37 +++++++++- pkg/ride/tree_expand.go | 74 ++++++++++++++----- pkg/ride/tree_expand_test.go | 119 +++++++++++++++++++++++++++++-- 9 files changed, 340 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index ae611d9daa..b6cc611464 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coocood/freecache v1.1.0 github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect github.com/ericlagergren/decimal v0.0.0-20190912144844-2c3e3e1ef942 - github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4 + github.com/frozen/immutable_map v0.0.0-20210311111814-e8c80004af78 github.com/fxamacker/cbor/v2 v2.2.0 github.com/go-chi/chi v4.0.3+incompatible github.com/golang/mock v1.4.3 diff --git a/go.sum b/go.sum index 718541bde3..ffa1d027e1 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/frozen/immutable_map v0.0.0-20210224161639-a72734704977 h1:ViTVPEPcu1 github.com/frozen/immutable_map v0.0.0-20210224161639-a72734704977/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4 h1:QJdN7XRRAp+ZEGl0ha5rjuL5/XJrEMtht0csVoVcvHA= github.com/frozen/immutable_map v0.0.0-20210226113144-8441e20b6fa4/go.mod h1:wIufmkixG0KtX1l5NNbSwlp/GIHJ0tUnMO/uXKUs9LU= +github.com/frozen/immutable_map v0.0.0-20210311111814-e8c80004af78 h1:i0awoKc80g63OC8xPcXFBbulGtHVbrA+/eT/WYjuSGM= +github.com/frozen/immutable_map v0.0.0-20210311111814-e8c80004af78/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= diff --git a/pkg/ride/compiler2_test.go b/pkg/ride/compiler2_test.go index 3099599605..5d39436575 100644 --- a/pkg/ride/compiler2_test.go +++ b/pkg/ride/compiler2_test.go @@ -1514,3 +1514,116 @@ func TestShadowedVariable(t *testing.T) { require.NoError(t, err) require.Equal(t, true, rs.Result()) } + +/* + +{-# 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 TestNoDuplicateCallToState2(t *testing.T) { + source := `AAIDAAAAAAAAABYIARIAEgQKAgEIEgQKAggBEgQKAggBAAAAGgEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBoAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQAAAAAAAAAAAAEAAAAOZ2V0U3RyaW5nQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABB0AAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABlN0cmluZwQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQIAAAAAAQAAAAxnZXRCb29sQnlLZXkAAAABAAAAA2tleQQAAAAHJG1hdGNoMAkABBsAAAACBQAAAAR0aGlzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAB0Jvb2xlYW4EAAAAAWEFAAAAByRtYXRjaDAFAAAAAWEHAQAAABhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkAAAACAAAAB2FkZHJlc3MAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIJAQAAABxAZXh0clVzZXIoYWRkcmVzc0Zyb21TdHJpbmcpAAAAAQUAAAAHYWRkcmVzcwUAAAADa2V5AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAAWEFAAAAByRtYXRjaDAFAAAAAWEAAAAAAAAAAAABAAAAGGdldFN0cmluZ0J5QWRkcmVzc0FuZEtleQAAAAIAAAAHYWRkcmVzcwAAAANrZXkEAAAAByRtYXRjaDAJAAQdAAAAAgUAAAAHYWRkcmVzcwUAAAADa2V5AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAAZTdHJpbmcEAAAAAWEFAAAAByRtYXRjaDAFAAAAAWECAAAAAAAAAAASTmV1dHJpbm9Bc3NldElkS2V5AgAAABFuZXV0cmlub19hc3NldF9pZAAAAAATTmV1dHJpbm9Db250cmFjdEtleQIAAAARbmV1dHJpbm9fY29udHJhY3QAAAAACkJhbGFuY2VLZXkCAAAAC3JwZF9iYWxhbmNlAAAAABBMYXN0Q29uZmlybVR4S2V5AgAAAA9sYXN0X2NvbmZpcm1fdHgAAAAAEkNvbnRyb2xDb250cmFjdEtleQIAAAAQY29udHJvbF9jb250cmFjdAEAAAARZ2V0VXNlckJhbGFuY2VLZXkAAAACAAAABW93bmVyAAAAB2Fzc2V0SWQJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgUAAAAKQmFsYW5jZUtleQIAAAABXwUAAAAHYXNzZXRJZAIAAAABXwUAAAAFb3duZXIBAAAAFWdldENvbnRyYWN0QmFsYW5jZUtleQAAAAEAAAAHYXNzZXRJZAkAASwAAAACCQABLAAAAAIFAAAACkJhbGFuY2VLZXkCAAAAAV8FAAAAB2Fzc2V0SWQBAAAAFGdldEV4cGlyZVByb3Bvc2FsS2V5AAAAAQAAAARoYXNoCQABLAAAAAIJAAEsAAAAAgIAAAAPcHJvcG9zYWxfZXhwaXJlAgAAAAFfBQAAAARoYXNoAQAAABNnZXRPd25lclByb3Bvc2FsS2V5AAAAAQAAAARoYXNoCQABLAAAAAIJAAEsAAAAAgIAAAAOcHJvcG9zYWxfb3duZXICAAAAAV8FAAAABGhhc2gBAAAAF2dldEFyZ3VtZW50c1Byb3Bvc2FsS2V5AAAAAQAAAARoYXNoCQABLAAAAAIJAAEsAAAAAgIAAAAScHJvcG9zYWxfYXJndW1lbnRzAgAAAAFfBQAAAARoYXNoAQAAAApnZXRWb3RlS2V5AAAAAgAAAAVvd25lcgAAAARoYXNoCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAADXByb3Bvc2FsX3ZvdGUCAAAAAV8FAAAABW93bmVyAgAAAAFfBQAAAARoYXNoAAAAABBuZXV0cmlub0NvbnRyYWN0CQEAAAAcQGV4dHJVc2VyKGFkZHJlc3NGcm9tU3RyaW5nKQAAAAEJAQAAAA5nZXRTdHJpbmdCeUtleQAAAAEFAAAAE05ldXRyaW5vQ29udHJhY3RLZXkAAAAAD2NvbnRyb2xDb250cmFjdAkBAAAAHEBleHRyVXNlcihhZGRyZXNzRnJvbVN0cmluZykAAAABCQEAAAAYZ2V0U3RyaW5nQnlBZGRyZXNzQW5kS2V5AAAAAgUAAAAQbmV1dHJpbm9Db250cmFjdAUAAAASQ29udHJvbENvbnRyYWN0S2V5AAAAAA1sYXN0Q29uZmlybVR4CQEAAAAYZ2V0U3RyaW5nQnlBZGRyZXNzQW5kS2V5AAAAAgUAAAAPY29udHJvbENvbnRyYWN0BQAAABBMYXN0Q29uZmlybVR4S2V5AAAAAA9uZXV0cmlub0Fzc2V0SWQJAAJZAAAAAQkBAAAAGGdldFN0cmluZ0J5QWRkcmVzc0FuZEtleQAAAAIFAAAAEG5ldXRyaW5vQ29udHJhY3QFAAAAEk5ldXRyaW5vQXNzZXRJZEtleQEAAAASZ2V0Q29udHJhY3RCYWxhbmNlAAAAAQAAAAdhc3NldElkCQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABCQEAAAAVZ2V0Q29udHJhY3RCYWxhbmNlS2V5AAAAAQUAAAAHYXNzZXRJZAEAAAAOZ2V0VXNlckJhbGFuY2UAAAACAAAABW93bmVyAAAAB2Fzc2V0SWQJAQAAAA5nZXROdW1iZXJCeUtleQAAAAEJAQAAABFnZXRVc2VyQmFsYW5jZUtleQAAAAIFAAAABW93bmVyBQAAAAdhc3NldElkAQAAABFnZXRFeHBpcmVQcm9wb3NhbAAAAAEAAAAEaGFzaAkBAAAADmdldE51bWJlckJ5S2V5AAAAAQkBAAAAFGdldEV4cGlyZVByb3Bvc2FsS2V5AAAAAQUAAAAEaGFzaAEAAAAQZ2V0T3duZXJQcm9wb3NhbAAAAAEAAAAEaGFzaAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQkBAAAAE2dldE93bmVyUHJvcG9zYWxLZXkAAAABBQAAAARoYXNoAQAAABRnZXRBcmd1bWVudHNQcm9wb3NhbAAAAAEAAAAEaGFzaAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQkBAAAAF2dldEFyZ3VtZW50c1Byb3Bvc2FsS2V5AAAAAQUAAAAEaGFzaAEAAAAHZ2V0Vm90ZQAAAAIAAAAFb3duZXIAAAAEaGFzaAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQkBAAAACmdldFZvdGVLZXkAAAACBQAAAAVvd25lcgUAAAAEaGFzaAAAAAQAAAABaQEAAAAMbG9ja05ldXRyaW5vAAAAAAQAAAADcG10CQEAAAAHZXh0cmFjdAAAAAEIBQAAAAFpAAAAB3BheW1lbnQDCQEAAAACIT0AAAACCAUAAAADcG10AAAAB2Fzc2V0SWQFAAAAD25ldXRyaW5vQXNzZXRJZAkAAAIAAAABAgAAABBjYW4gdXNlIG5ldXRyaW5vBAAAAAdhY2NvdW50CQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgQAAAANYXNzZXRJZFN0cmluZwkAAlgAAAABCQEAAAAFdmFsdWUAAAABCAUAAAADcG10AAAAB2Fzc2V0SWQJAQAAAAhXcml0ZVNldAAAAAEJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIJAQAAABVnZXRDb250cmFjdEJhbGFuY2VLZXkAAAABBQAAAA1hc3NldElkU3RyaW5nCQAAZAAAAAIJAQAAABJnZXRDb250cmFjdEJhbGFuY2UAAAABBQAAAA1hc3NldElkU3RyaW5nCAUAAAADcG10AAAABmFtb3VudAkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkBAAAAEWdldFVzZXJCYWxhbmNlS2V5AAAAAgUAAAAHYWNjb3VudAUAAAANYXNzZXRJZFN0cmluZwkAAGQAAAACCQEAAAAOZ2V0VXNlckJhbGFuY2UAAAACBQAAAAdhY2NvdW50BQAAAA1hc3NldElkU3RyaW5nCAUAAAADcG10AAAABmFtb3VudAUAAAADbmlsAAAAAWkBAAAADnVubG9ja05ldXRyaW5vAAAAAgAAAAx1bmxvY2tBbW91bnQAAAANYXNzZXRJZFN0cmluZwQAAAAHYWNjb3VudAkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIEAAAAB2Fzc2V0SWQJAAJZAAAAAQUAAAANYXNzZXRJZFN0cmluZwQAAAAHYmFsYW5jZQkAAGUAAAACCQEAAAAOZ2V0VXNlckJhbGFuY2UAAAACBQAAAAdhY2NvdW50BQAAAA1hc3NldElkU3RyaW5nBQAAAAx1bmxvY2tBbW91bnQDCQAAZgAAAAIAAAAAAAAAAAAFAAAAB2JhbGFuY2UJAAACAAAAAQIAAAAOaW52YWxpZCBhbW91bnQDCQEAAAACIT0AAAACBQAAAAdhc3NldElkBQAAAA9uZXV0cmlub0Fzc2V0SWQJAAACAAAAAQIAAAAQY2FuIHVzZSBuZXV0cmlubwkBAAAADFNjcmlwdFJlc3VsdAAAAAIJAQAAAAhXcml0ZVNldAAAAAEJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIJAQAAABVnZXRDb250cmFjdEJhbGFuY2VLZXkAAAABBQAAAA1hc3NldElkU3RyaW5nCQAAZQAAAAIJAQAAABJnZXRDb250cmFjdEJhbGFuY2UAAAABBQAAAA1hc3NldElkU3RyaW5nBQAAAAx1bmxvY2tBbW91bnQJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIJAQAAABFnZXRVc2VyQmFsYW5jZUtleQAAAAIFAAAAB2FjY291bnQFAAAADWFzc2V0SWRTdHJpbmcFAAAAB2JhbGFuY2UFAAAAA25pbAkBAAAAC1RyYW5zZmVyU2V0AAAAAQkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCQEAAAAcQGV4dHJVc2VyKGFkZHJlc3NGcm9tU3RyaW5nKQAAAAEFAAAAB2FjY291bnQFAAAADHVubG9ja0Ftb3VudAUAAAAPbmV1dHJpbm9Bc3NldElkBQAAAANuaWwAAAABaQEAAAAEdm90ZQAAAAIAAAAEaGFzaAAAAA1pbmRleEFyZ3VtZW50BAAAAAlhcmd1bWVudHMJAAS1AAAAAgkBAAAAFGdldEFyZ3VtZW50c1Byb3Bvc2FsAAAAAQUAAAAEaGFzaAIAAAABLAQAAAAIYXJndW1lbnQJAAGRAAAAAgUAAAAJYXJndW1lbnRzBQAAAA1pbmRleEFyZ3VtZW50AwkAAGYAAAACBQAAAAZoZWlnaHQJAQAAABFnZXRFeHBpcmVQcm9wb3NhbAAAAAEFAAAABGhhc2gJAAACAAAAAQIAAAATcHJvcG9zYWwgaXMgZXhwaXJlZAkBAAAACFdyaXRlU2V0AAAAAQkABEwAAAACCQEAAAAJRGF0YUVudHJ5AAAAAgkBAAAACmdldFZvdGVLZXkAAAACCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgUAAAAEaGFzaAUAAAAIYXJndW1lbnQFAAAAA25pbAAAAAFpAQAAAA5jcmVhdGVQcm9wb3NhbAAAAAIAAAAJYXJndW1lbnRzAAAADGV4cGFpckhlaWdodAQAAAAEaGFzaAkAAlgAAAABCQAB9QAAAAEJAADLAAAAAgkAAMsAAAACCQABmwAAAAEFAAAACWFyZ3VtZW50cwkAAZoAAAABBQAAAAxleHBhaXJIZWlnaHQIBQAAAAFpAAAAD2NhbGxlclB1YmxpY0tleQMJAQAAAAIhPQAAAAIJAQAAABBnZXRPd25lclByb3Bvc2FsAAAAAQUAAAAEaGFzaAIAAAAACQAAAgAAAAECAAAAEXByb3Bvc2FsIGlzIGV4aXN0CQEAAAAIV3JpdGVTZXQAAAABCQAETAAAAAIJAQAAAAlEYXRhRW50cnkAAAACCQEAAAAUZ2V0RXhwaXJlUHJvcG9zYWxLZXkAAAABBQAAAARoYXNoBQAAAAxleHBhaXJIZWlnaHQJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIJAQAAABNnZXRPd25lclByb3Bvc2FsS2V5AAAAAQUAAAAEaGFzaAkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIJAARMAAAAAgkBAAAACURhdGFFbnRyeQAAAAIJAQAAABdnZXRBcmd1bWVudHNQcm9wb3NhbEtleQAAAAEFAAAABGhhc2gFAAAACWFyZ3VtZW50cwUAAAADbmlsAAAAAQAAAAJ0eAEAAAAGdmVyaWZ5AAAAAAkAAAAAAAACBQAAAA1sYXN0Q29uZmlybVR4CQACWAAAAAEIBQAAAAJ0eAAAAAJpZPY+ef8=` + + 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": + return &proto.StringDataEntry{Value: "3MVHscMp4C3JjeaEiZB6fxeomPZdYEHyamY"}, nil + case "control_contract": + return &proto.StringDataEntry{Value: "3MQdbE6dK59FHxh5rf4biQdyXhdEf3L1R5W"}, nil + case "last_confirm_tx": + return &proto.StringDataEntry{Value: "3M9uzVzrAAYEKSHXzKaPhw7iQjwDi9BRJysHZHpbqXJm"}, nil + + } + panic(key) + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + } + env := &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return state + }, + schemeFunc: func() byte { + return 'S' + }, + thisFunc: func() rideType { + b := [26]byte{1, 83, 122, 149, 83, 66, 227, 147, 59, 198, 33, 214, 105, 255, 17, 4, 168, 100, 213, 112, 143, 31, 192, 98, 166, 126} + return rideAddress(b) + }, + heightFunc: func() rideInt { + return 1 + }, + } + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + require.NoError(t, err) + assert.NotNil(t, tree) + + rs1, err := CallTreeVerifier(env, tree) + //rs1, err := CallTreeVerifier(env, MustExpand(tree)) + require.NoError(t, err) + for _, c := range rs1.Calls() { + t.Log(c) + } + t.Log("") + t.Log("") + + script, err := CompileVerifier("", MustExpand(tree)) + require.NoError(t, err) + assert.NotNil(t, script) + + rs2, err := script.Verify(env) + require.NoError(t, err) + for _, c := range rs2.Calls() { + t.Log(c) + } + //t.Log(rs.Calls()) + require.NoError(t, err) + + //t.Log(rs.Calls()) + require.False(t, rs2.Result()) +} diff --git a/pkg/ride/compiler_state.go b/pkg/ride/compiler_state.go index f2a11046de..0464821c63 100644 --- a/pkg/ride/compiler_state.go +++ b/pkg/ride/compiler_state.go @@ -83,7 +83,7 @@ func (a *params) constant(value rideType) constantDeferred { func reference(_ Fsm, params params, name string) constantDeferred { pos, ok := params.r.getAssigment(name) if !ok { - panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID)) + panic(fmt.Sprintf("reference `%s` not found, tx %s", name, params.txID)) } return NewConstantDeferred(pos) } diff --git a/pkg/ride/decompiler.go b/pkg/ride/decompiler.go index 49462a621f..b59f8f3fae 100644 --- a/pkg/ride/decompiler.go +++ b/pkg/ride/decompiler.go @@ -50,6 +50,9 @@ var defuncs = map[string]func(s *strings.Builder, name string, nodes []Node, f d "101": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, "-", nodes, f) }, + "102": func(s *strings.Builder, name string, nodes []Node, f detreeType) { + infix(s, ">", nodes, f) + }, "103": func(s *strings.Builder, name string, nodes []Node, f detreeType) { infix(s, ">=", nodes, f) }, diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index 8f30948be7..e14182be90 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -2,7 +2,6 @@ package ride import ( "github.com/pkg/errors" - "github.com/stretchr/testify/assert" "github.com/wavesplatform/gowaves/pkg/proto" "go.uber.org/zap" ) @@ -23,6 +22,7 @@ func CallVmVerifier(txID string, env RideEnvironment, compiled *Executable) (Rid } func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) (RideResult, error) { + tree = MustExpand(tree) r, err := CallVmVerifier(txID, env, exe) if err != nil { return nil, errors.Wrap(err, "vm verifier") @@ -33,6 +33,7 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) } if !r.Eq(r2) { + zap.S().Error(DecompileTree(tree)) c1 := r.Calls() c2 := r2.Calls() max := len(c1) @@ -71,7 +72,7 @@ func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, } func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - rs1, err := CallTreeFunction(txID, env, tree, name, args) + rs1, err := CallTreeFunction(txID, env, MustExpand(tree), name, args) if err != nil { return nil, errors.Wrap(err, "call function by tree") } @@ -80,6 +81,7 @@ func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, return rs2, errors.Wrap(err, "call function by vm") } if !rs1.Eq(rs2) { + zap.S().Error(DecompileTree(tree)) c1 := rs1.Calls() c2 := rs2.Calls() max := len(c1) @@ -99,15 +101,15 @@ func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, } } - ac1 := rs1.ScriptActions() - ac2 := rs2.ScriptActions() - for i := range ac1 { - zap.S().Errorf("%d %s Action %+v", i, txID, ac1[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value) - zap.S().Errorf("%d %s Action %+v", i, txID, ac2[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value) - zap.S().Errorf("Eq %+v", assert.ObjectsAreEqual(ac1[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value, ac2[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value)) - break - //zap.S().Errorf(i, txID, " Action ", ac2[i]) - } + //ac1 := rs1.ScriptActions() + //ac2 := rs2.ScriptActions() + //for i := range ac1 { + // //zap.S().Errorf("%d %s Action %+v", i, txID, ac1[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value) + // //zap.S().Errorf("%d %s Action %+v", i, txID, ac2[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value) + // //zap.S().Errorf("Eq %+v", assert.ObjectsAreEqual(ac1[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value, ac2[i].(*proto.DataEntryScriptAction).Entry.(*proto.BinaryDataEntry).Value)) + // break + // //zap.S().Errorf(i, txID, " Action ", ac2[i]) + //} return nil, errors.New("R1 != R2: failed to call account script on transaction ") } diff --git a/pkg/ride/tree_evaluation_test.go b/pkg/ride/tree_evaluation_test.go index 8ff628051e..92dad33827 100644 --- a/pkg/ride/tree_evaluation_test.go +++ b/pkg/ride/tree_evaluation_test.go @@ -3528,9 +3528,44 @@ func TestTreeShadowedVariable(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) tree = MustExpand(tree) - require.Equal(t, "(let height = { height }; height != 0)", DecompileTree(tree)) + //require.Equal(t, "(let height = { height }; height != 0)", DecompileTree(tree)) result, err := CallTreeVerifier(defaultEnv, tree) require.NoError(t, err) require.Equal(t, true, result.Result()) } + +/** +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE EXPRESSION #-} +func xx(height: Int) = { + height +} + +func yy(height: Int) = { + xx(height) +} + +yy(height) == 1 +*/ +func TestTreeShadowedVariable2(t *testing.T) { + source := `AwoBAAAAAnh4AAAAAQAAAAZoZWlnaHQFAAAABmhlaWdodAoBAAAAAnl5AAAAAQAAAAZoZWlnaHQJAQAAAAJ4eAAAAAEFAAAABmhlaWdodAkAAAAAAAACCQEAAAACeXkAAAABBQAAAAZoZWlnaHQAAAAAAAAAAAHVMsKD` + + 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$yy = { height }; let height$xx = { height$yy }; height$xx == 1)", DecompileTree(tree)) + + result, err := CallTreeVerifier(defaultEnv, tree) + require.NoError(t, err) + require.Equal(t, false, result.Result()) +} + +func TestTtt(t *testing.T) { + r := newNameReplacements().addAll("$yy", []string{"address", "key"}) + _ = r +} diff --git a/pkg/ride/tree_expand.go b/pkg/ride/tree_expand.go index 9d7a287f8c..7db704075b 100644 --- a/pkg/ride/tree_expand.go +++ b/pkg/ride/tree_expand.go @@ -39,6 +39,38 @@ func (a expandScope) get1(name string) *FunctionDeclarationNode { return nil } +type nameReplacements struct { + im *im.Map +} + +func newNameReplacements() nameReplacements { + return nameReplacements{ + im: im.New(), + } +} + +func (a nameReplacements) add(original string, replacement string) nameReplacements { + return nameReplacements{ + im: a.im.Insert([]byte(original), replacement), + } +} + +func (a nameReplacements) addAll(postfix string, args []string) nameReplacements { + tmp := a + for _, arg := range args { + tmp = tmp.add(arg, arg+postfix) + } + return tmp +} + +func (a nameReplacements) get(name string) string { + inf, ok := a.im.Get([]byte(name)) + if ok { + return inf.(string) + } + return name +} + func Expand(t *Tree) (*Tree, error) { if t.Expanded { return t, nil @@ -48,10 +80,10 @@ func Expand(t *Tree) (*Tree, error) { for _, f := range t.Declarations { v, ok := f.(*FunctionDeclarationNode) if !ok { - declarations = append(declarations, expand(scope, f)) + declarations = append(declarations, expand(scope, f, newNameReplacements())) continue } - v2 := cloneFuncDecl(v, expand(scope, v.Body), nil) + v2 := cloneFuncDecl(v, expand(scope, v.Body, newNameReplacements().addAll("$"+v.Name, v.Arguments)), nil) scope = scope.add(v.Name, v2) } functions := make([]Node, 0, len(t.Functions)) @@ -61,15 +93,15 @@ func Expand(t *Tree) (*Tree, error) { return nil, errors.Errorf("can't expand tree. Expected function to be `*FunctionDeclarationNode`, found %T", f) } v2 := v.Clone().(*FunctionDeclarationNode) - v2.Body = expand(scope, v.Body) + v2.Body = expand(scope, v.Body, newNameReplacements()) scope = scope.add(v.Name, v2) functions = append(functions, v2) } verifier := t.Verifier if t.IsDApp() && t.HasVerifier() { - verifier = cloneFuncDecl(t.Verifier.(*FunctionDeclarationNode), expand(scope, t.Verifier.(*FunctionDeclarationNode).Body), nil) + verifier = cloneFuncDecl(t.Verifier.(*FunctionDeclarationNode), expand(scope, t.Verifier.(*FunctionDeclarationNode).Body, newNameReplacements()), nil) } else { - verifier = expand(scope, t.Verifier) + verifier = expand(scope, t.Verifier, newNameReplacements()) } return &Tree{ Digest: t.Digest, @@ -92,7 +124,7 @@ func MustExpand(t *Tree) *Tree { return rs } -func expand(scope expandScope, node Node) Node { +func expand(scope expandScope, node Node, replacements nameReplacements) Node { switch v := node.(type) { case *FunctionCallNode: f, ok := scope.get(v.Name) @@ -100,8 +132,8 @@ func expand(scope expandScope, node Node) Node { root := f.Body for i := len(v.Arguments) - 1; i >= 0; i-- { root = &AssignmentNode{ - Name: f.Arguments[i], - Expression: expand(scope, v.Arguments[i]), + Name: fmt.Sprintf("%s$%s", f.Arguments[i], f.Name), + Expression: expand(scope, v.Arguments[i], replacements), Block: root, } } @@ -110,35 +142,41 @@ func expand(scope expandScope, node Node) Node { return &FunctionCallNode{ Name: v.Name, Arguments: v.Arguments.Map(func(node Node) Node { - return expand(scope, node) + return expand(scope, node, replacements) }), } } case *FunctionDeclarationNode: - body := expand(scope, v.Body) + + body := expand(scope, v.Body, replacements.addAll("$"+v.Name, v.Arguments)) v2 := cloneFuncDecl(v, body, nil) - block := expand(scope.add(v.Name, v2), v.Block) + block := expand(scope.add(v.Name, v2), v.Block, replacements) return block case *AssignmentNode: return &AssignmentNode{ Name: v.Name, - Block: expand(scope, v.Block), - Expression: expand(scope, v.Expression), + Block: expand(scope, v.Block, replacements), + Expression: expand(scope, v.Expression, replacements), } case nil: return node case *ConditionalNode: return &ConditionalNode{ - Condition: expand(scope, v.Condition), - TrueExpression: expand(scope, v.TrueExpression), - FalseExpression: expand(scope, v.FalseExpression), + Condition: expand(scope, v.Condition, replacements), + TrueExpression: expand(scope, v.TrueExpression, replacements), + FalseExpression: expand(scope, v.FalseExpression, replacements), } case *ReferenceNode: + return &ReferenceNode{Name: replacements.get(v.Name)} + case *StringNode, *LongNode, *BytesNode, *BooleanNode: return v - case *StringNode, *LongNode, *BytesNode, *BooleanNode, *PropertyNode: - return v + case *PropertyNode: + return &PropertyNode{ + Name: v.Name, + Object: expand(scope, v.Object, replacements), + } default: panic(fmt.Sprintf("unknown %T", node)) return v.Clone() diff --git a/pkg/ride/tree_expand_test.go b/pkg/ride/tree_expand_test.go index db24bcfa9c..9f3c28f8db 100644 --- a/pkg/ride/tree_expand_test.go +++ b/pkg/ride/tree_expand_test.go @@ -5,11 +5,13 @@ import ( "encoding/base64" "errors" "fmt" + "strconv" "strings" "testing" "github.com/stretchr/testify/require" "github.com/wavesplatform/gowaves/pkg/proto" + "github.com/wavesplatform/gowaves/pkg/util/byte_helpers" //"github.com/wavesplatform/gowaves/pkg/proto" "github.com/wavesplatform/gowaves/pkg/types" @@ -183,10 +185,6 @@ func TestTreeExpand11(t *testing.T) { require.NoError(t, err) require.Equal(t, true, rs.Result()) }) - - t.Run("", func(t *testing.T) { - - }) } /** @@ -357,3 +355,116 @@ func TestExpandSmthWrote3(t *testing.T) { ////require.Equal(t, 2, len(rs.Calls())) require.Equal(t, true, rs.Result()) } + +/* +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE EXPRESSION #-} +func xx(height: Int) = { + height +} + +xx(height) == 1 +*/ +func TestWithHeight(t *testing.T) { + source := `AwoBAAAAAnh4AAAAAQAAAAZoZWlnaHQFAAAABmhlaWdodAkAAAAAAAACCQEAAAACeHgAAAABBQAAAAZoZWlnaHQAAAAAAAAAAAHS0qks` + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + tree = MustExpand(tree) + t.Log(DecompileTree(tree)) + //require.NoError(t, err) + //require.NotNil(t, tree) + // + script, err := CompileTree("", tree) + require.NoError(t, err) + + //rsT, err := CallTreeVerifier(nil, tree) + //require.NoError(t, err) + //_ = rsT + // + //rs, err := script.Invoke(defaultEnv, "addBuyBondOrder", []rideType{rideInt(1398601), rideString("")}) + rs, err := script.Verify(defaultEnv) + require.NoError(t, err) + ////require.Equal(t, 2, len(rs.Calls())) + require.Equal(t, true, rs.Result()) +} + +/* +{-# STDLIB_VERSION 3 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE EXPRESSION #-} + + +*/ +func TestWithHeight2(t *testing.T) { + source := `AAIEAAAAAAAAAAgIAhIECgIIAQAAAB8AAAAABWFkbWluAQAAACCnVErqp8ibQ55WtRdh6dN0wQFoQ9ny+0uTALD786XdOAAAAAAHYXNzZXRJZAkAAlkAAAABAgAAACwzVGFmM1RBSldEeUJzQXN5ZGRiVTFwbjVkV2VjQ3doajRra0UxakZKb0RDawAAAAAETk9ORQIAAAALbm8gZXhpc3RpbmcAAAAABExJU1QJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAECAAAAIzNNa3RKZ1YyZVRtY0NxdHlRYWVxaWlIa1ExZVkzRUg1VGRiAQAAAAtmZXRjaFN0cmluZwAAAAIAAAAFYWxpYXMAAAADa2V5BAAAAAckbWF0Y2gwCQAEHQAAAAIFAAAABWFsaWFzBQAAAANrZXkDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABlN0cmluZwQAAAABYQUAAAAHJG1hdGNoMAUAAAABYQUAAAAETk9ORQEAAAAMZmV0Y2hJbnRlZ2VyAAAAAgAAAAVhbGlhcwAAAANrZXkEAAAAByRtYXRjaDAJAAQaAAAAAgUAAAAFYWxpYXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAFhBQAAAAckbWF0Y2gwBQAAAAFhAAAAAAAAAAAAAQAAAAdnZXREYXBwAAAAAAkBAAAAC2ZldGNoU3RyaW5nAAAAAgUAAAAEdGhpcwIAAAALZGFwcEFkZHJlc3MBAAAACWdldE1hc3RlcgAAAAAJAQAAAAtmZXRjaFN0cmluZwAAAAIFAAAABHRoaXMCAAAADW1hc3RlckFkZHJlc3MBAAAAEGdldEFjY291bnRTdGF0dXMAAAABAAAAB2FkZHJlc3MJAQAAABFAZXh0ck5hdGl2ZSgxMDUxKQAAAAIFAAAABExJU1QJAAEsAAAAAgUAAAAHYWRkcmVzcwIAAAAHX2FjdGl2ZQEAAAAWZ2V0TGltaXRUb3RhbEFtb3VudEtleQAAAAEAAAAFbGltaXQJAAEsAAAAAgIAAAATbGltaXRfdG90YWxfYW1vdW50XwUAAAAFbGltaXQBAAAAGGdldExpbWl0VG90YWxBbW91bnRWYWx1ZQAAAAEAAAAFbGltaXQJAQAAAAxmZXRjaEludGVnZXIAAAACBQAAAAR0aGlzCQEAAAAWZ2V0TGltaXRUb3RhbEFtb3VudEtleQAAAAEFAAAABWxpbWl0AQAAAA5nZXRUb3RhbEFtb3VudAAAAAAJAQAAAAxmZXRjaEludGVnZXIAAAACBQAAAAR0aGlzAgAAAAx0b3RhbF9hbW91bnQBAAAACmdldExpc3RLZXkAAAACAAAAB2FkZHJlc3MAAAAJbGltaXREYXRlBAAAAApzZWVkUGhyYXNlCQABLAAAAAIFAAAAB2FkZHJlc3MFAAAACWxpbWl0RGF0ZQkAASwAAAACAgAAAAdsaXN0ZWRfCQACWAAAAAEJAAH3AAAAAQkAAZsAAAABBQAAAApzZWVkUGhyYXNlAQAAABBnZXRMaXN0QW1vdW50S2V5AAAAAQAAAAdsaXN0S2V5CQABLAAAAAIFAAAAB2xpc3RLZXkCAAAAB19hbW91bnQBAAAAD2dldExpc3RMaW1pdEtleQAAAAEAAAAHbGlzdEtleQkAASwAAAACBQAAAAdsaXN0S2V5AgAAAAZfbGltaXQBAAAAD2dldExpc3RPd25lcktleQAAAAEAAAAHbGlzdEtleQkAASwAAAACBQAAAAdsaXN0S2V5AgAAAAZfb3duZXIBAAAAE2dldExpc3RVbml0UHJpY2VLZXkAAAABAAAAB2xpc3RLZXkJAAEsAAAAAgUAAAAHbGlzdEtleQIAAAAKX3VuaXRQcmljZQEAAAAVZ2V0TGlzdERlc2NyaXB0aW9uS2V5AAAAAQAAAAdsaXN0S2V5CQABLAAAAAIFAAAAB2xpc3RLZXkCAAAADF9kZXNjcmlwdGlvbgEAAAASZ2V0TGlzdEFtb3VudFZhbHVlAAAAAQAAAAdsaXN0S2V5CQEAAAAMZmV0Y2hJbnRlZ2VyAAAAAgUAAAAEdGhpcwkBAAAAEGdldExpc3RBbW91bnRLZXkAAAABBQAAAAdsaXN0S2V5AQAAABFnZXRMaXN0TGltaXRWYWx1ZQAAAAEAAAAHbGlzdEtleQkBAAAAC2ZldGNoU3RyaW5nAAAAAgUAAAAEdGhpcwkBAAAAD2dldExpc3RMaW1pdEtleQAAAAEFAAAAB2xpc3RLZXkBAAAAEWdldExpc3RPd25lclZhbHVlAAAAAQAAAAdsaXN0S2V5CQEAAAALZmV0Y2hTdHJpbmcAAAACBQAAAAR0aGlzCQEAAAAPZ2V0TGlzdE93bmVyS2V5AAAAAQUAAAAHbGlzdEtleQEAAAAVZ2V0TGlzdFVuaXRQcmljZVZhbHVlAAAAAQAAAAdsaXN0S2V5CQEAAAAMZmV0Y2hJbnRlZ2VyAAAAAgUAAAAEdGhpcwkBAAAAE2dldExpc3RVbml0UHJpY2VLZXkAAAABBQAAAAdsaXN0S2V5AQAAABdnZXRMaXN0RGVzY3JpcHRpb25WYWx1ZQAAAAEAAAAHbGlzdEtleQkBAAAAC2ZldGNoU3RyaW5nAAAAAgUAAAAEdGhpcwkBAAAAFWdldExpc3REZXNjcmlwdGlvbktleQAAAAEFAAAAB2xpc3RLZXkBAAAAC2dldE93bmVkS2V5AAAAAgAAAAVvd25lcgAAAAVsaW1pdAQAAAAKc2VlZFBocmFzZQkAASwAAAACBQAAAAVvd25lcgUAAAAFbGltaXQJAAEsAAAAAgIAAAAGb3duZWRfCQACWAAAAAEJAAH3AAAAAQkAAZsAAAABBQAAAApzZWVkUGhyYXNlAQAAABFnZXRPd25lZEFtb3VudEtleQAAAAEAAAAIb3duZWRLZXkJAAEsAAAAAgUAAAAIb3duZWRLZXkCAAAAB19hbW91bnQBAAAAEGdldE93bmVkTGltaXRLZXkAAAABAAAACG93bmVkS2V5CQABLAAAAAIFAAAACG93bmVkS2V5AgAAAAZfbGltaXQBAAAAEGdldE93bmVkT3duZXJLZXkAAAABAAAACG93bmVkS2V5CQABLAAAAAIFAAAACG93bmVkS2V5AgAAAAZfb3duZXIBAAAAE2dldE93bmVkQW1vdW50VmFsdWUAAAABAAAACG93bmVkS2V5CQEAAAAMZmV0Y2hJbnRlZ2VyAAAAAgUAAAAEdGhpcwkBAAAAEWdldE93bmVkQW1vdW50S2V5AAAAAQUAAAAIb3duZWRLZXkBAAAAEmdldE93bmVkTGltaXRWYWx1ZQAAAAEAAAAIb3duZWRLZXkJAQAAAAtmZXRjaFN0cmluZwAAAAIFAAAABHRoaXMJAQAAABBnZXRPd25lZExpbWl0S2V5AAAAAQUAAAAIb3duZWRLZXkBAAAAC3VwZGF0ZU93bmVkAAAAAwAAAAVvd25lcgAAAAZhbW91bnQAAAAFbGltaXQEAAAACG93bmVkS2V5CQEAAAALZ2V0T3duZWRLZXkAAAACBQAAAAVvd25lcgUAAAAFbGltaXQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABFnZXRPd25lZEFtb3VudEtleQAAAAEFAAAACG93bmVkS2V5CQAAZAAAAAIJAQAAABNnZXRPd25lZEFtb3VudFZhbHVlAAAAAQUAAAAIb3duZWRLZXkFAAAABmFtb3VudAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAQZ2V0T3duZWRMaW1pdEtleQAAAAEFAAAACG93bmVkS2V5BQAAAAVsaW1pdAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAQZ2V0T3duZWRPd25lcktleQAAAAEFAAAACG93bmVkS2V5BQAAAAVvd25lcgUAAAADbmlsAQAAAA10cmFuc2ZlclRva2VuAAAABAAAAAZzZW5kZXIAAAAJcmVjaXBpZW50AAAABmFtb3VudAAAAAVsaW1pdAkABE4AAAACCQEAAAALdXBkYXRlT3duZWQAAAADBQAAAAZzZW5kZXIJAQAAAAEtAAAAAQUAAAAGYW1vdW50BQAAAAVsaW1pdAkBAAAAC3VwZGF0ZU93bmVkAAAAAwUAAAAJcmVjaXBpZW50BQAAAAZhbW91bnQFAAAABWxpbWl0AAAAAQAAAAFpAQAAAAhwdXJjaGFzZQAAAAIAAAADa2V5AAAABmFtb3VudAQAAAAHaW52b2tlcgIAAAAjM01qQk4ya2lSQjZKbW9FVkVDNDJaTk1YOWlieDVpWjlNaWgEAAAACHN1cHBsaWVyCQEAAAAPZ2V0TGlzdE93bmVyS2V5AAAAAQUAAAADa2V5BAAAAAVsaW1pdAkBAAAAEWdldExpc3RMaW1pdFZhbHVlAAAAAQUAAAADa2V5CQAETgAAAAIJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwkBAAAAEUBleHRyTmF0aXZlKDEwNjIpAAAAAQUAAAAHaW52b2tlcgUAAAAGYW1vdW50BQAAAAdhc3NldElkCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAQZ2V0TGlzdEFtb3VudEtleQAAAAEFAAAAA2tleQkAAGUAAAACCQEAAAASZ2V0TGlzdEFtb3VudFZhbHVlAAAAAQUAAAADa2V5BQAAAAZhbW91bnQFAAAAA25pbAkBAAAADXRyYW5zZmVyVG9rZW4AAAAECQEAAAAHZ2V0RGFwcAAAAAAFAAAAB2ludm9rZXIFAAAABmFtb3VudAUAAAAFbGltaXQAAAAAWzckVA==` + + src, err := base64.StdEncoding.DecodeString(source) + require.NoError(t, err) + + tree, err := Parse(src) + tree = MustExpand(tree) + t.Log(DecompileTree(tree)) + //require.NoError(t, err) + //require.NotNil(t, tree) + // + var defaultState = &MockSmartState{ + NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { + return byte_helpers.TransferWithProofs.Transaction, nil + }, + RetrieveNewestBinaryEntryFunc: func(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { + return nil, errors.New("not found") + }, + RetrieveNewestIntegerEntryFunc: func(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { + v, err := strconv.ParseInt(key, 10, 64) + if err != nil { + return nil, err + } + return &proto.IntegerDataEntry{ + Value: v, + }, nil + }, + RetrieveNewestStringEntryFunc: func(account proto.Recipient, key string) (*proto.StringDataEntry, error) { + + panic("key " + key) + }, + } + + var defaultEnv = &MockRideEnvironment{ + transactionFunc: testTransferObject, + stateFunc: func() types.SmartState { + return defaultState + }, + schemeFunc: func() byte { + return 'S' + }, + thisFunc: func() rideType { + return rideAddress{} + }, + invocationFunc: func() rideObject { + return rideObject{} + }, + heightFunc: func() rideInt { + return rideInt(100500) + }, + } + + script, err := CompileTree("", tree) + require.NoError(t, err) + + //rsT, err := CallTreeVerifier(nil, tree) + //require.NoError(t, err) + //_ = rsT + // + //rs, err := script.Invoke(defaultEnv, "addBuyBondOrder", []rideType{rideInt(1398601), rideString("")}) + rs, err := script.Invoke(defaultEnv, "purchase", []rideType{rideString("listed_J5ALPF3Z2fbtNs3mP1nFRNvG4AJ9LgDdwdnK6bKzF22s"), rideInt(5000)}) + + for _, r := range rs.Calls() { + t.Log(r) + } + require.NoError(t, err) + require.Equal(t, true, rs.Result()) +} From 15d0cb02cc2b40f3ad17e2f4c9794e1c2bce7d7f Mon Sep 17 00:00:00 2001 From: frozen Date: Fri, 19 Mar 2021 12:15:30 +0300 Subject: [PATCH 48/55] Removed fmtcheck. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 45687bc4f8..a247f96a78 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ export GO111MODULE=on .PHONY: vendor vetcheck fmtcheck clean build gotest -all: vendor vetcheck fmtcheck build gotest mod-clean +all: vendor vetcheck build gotest mod-clean ver: @echo Building version: $(VERSION) From 2e6c5846f1e28247d7b2566cb4ee722374db126c Mon Sep 17 00:00:00 2001 From: frozen Date: Fri, 19 Mar 2021 12:37:17 +0300 Subject: [PATCH 49/55] Clean code in tree evaluator. --- pkg/ride/reverse_tree.go | 1 - pkg/ride/reversed_tree.go | 156 ------------------------------------- pkg/ride/tree_evaluator.go | 89 +-------------------- 3 files changed, 4 insertions(+), 242 deletions(-) delete mode 100644 pkg/ride/reverse_tree.go delete mode 100644 pkg/ride/reversed_tree.go diff --git a/pkg/ride/reverse_tree.go b/pkg/ride/reverse_tree.go deleted file mode 100644 index 73bfe8fec9..0000000000 --- a/pkg/ride/reverse_tree.go +++ /dev/null @@ -1 +0,0 @@ -package ride diff --git a/pkg/ride/reversed_tree.go b/pkg/ride/reversed_tree.go deleted file mode 100644 index 703819f71e..0000000000 --- a/pkg/ride/reversed_tree.go +++ /dev/null @@ -1,156 +0,0 @@ -package ride - -type RNode interface { - RNode() -} - -type RFunc struct { - Invocation string - Name string - Arguments []string - ArgumentsWithInvocation []string - Body RNode -} - -func (a *RFunc) RNode() {} - -type RLet struct { - Name string -} - -func (a *RLet) RNode() {} - -type RRet struct { -} - -func (a *RRet) RNode() {} - -type RCond struct { -} - -func (a *RCond) RNode() {} - -type RCondEnd struct { -} - -func (a *RCondEnd) RNode() {} - -type RCondTrue struct { -} - -func (a *RCondTrue) RNode() {} - -type RCondFalse struct { -} - -func (a *RCondFalse) RNode() {} - -type RFuncEnd struct { -} - -func (a *RFuncEnd) RNode() {} - -//type RCond struct { -// Cond RNode -// True RNode -// False RNode -// Assigments []*RLet -//} -// -//func (a *RCond) RNode() {} - -type RCall struct { - Name string - //Arguments []RNode - Argn uint16 - //Assigments []*RLet - //Next RNode -} - -func (a *RCall) RNode() {} - -//func reverseRnodes(a []RNode) []RNode { -// out := make([]RNode, len(a)) -// for i := 0; i < len(a); i++ { -// out[len(a)-1-i] = a[i] -// } -// return out -//} - -//func (a *RCall) CallTree() []RNode { -// d := []RNode{ -// a, -// } -// for i := len(a.Arguments) - 1; i >= 0; i-- { -// switch t := a.Arguments[i].(type) { -// case *RConst: -// d = append(d, a.Arguments[i]) -// case *RCall: -// d = append(d, t.CallTree()...) -// default: -// panic("") -// } -// } -// return d -//} - -// -//type RRef struct { -// Name string -// Assigments []*RLet -//} -// -//func (a *RRef) RNode() {} - -//type RLong struct { -// Value int64 -//} -// -//func (a *RLong) RNode() {} - -type RConst struct { - Value rideType -} - -func (a *RConst) RNode() {} - -type RProperty struct{} - -func (a *RProperty) RNode() {} - -//type RString struct { -// Value string -//} -// -//func (a *RString) RNode() {} - -//type RBoolean struct { -// Value bool -//} -// -//func (a *RBoolean) RNode() {} - -type RReferenceNode struct { - Name string -} - -func (a *RReferenceNode) RNode() {} - -type RStart struct { - Name string -} - -func (a *RStart) RNode() {} - -type RDef struct { - Name string - Arguments []string -} - -func (a *RDef) RNode() {} - -type RBody struct { - Name string -} - -func (a *RBody) RNode() {} diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index b8b1def21b..d3f268a496 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -92,18 +92,15 @@ type evaluationScope struct { cs varsCtx fs funcCtx system map[string]rideFunction - //user []esFunction - cl int + cl int } func (s *evaluationScope) declare(n Node) error { switch d := n.(type) { case *FunctionDeclarationNode: - //s.pushUserFunction(d) s.fs = s.fs.add(d.Name, d, s.cs) return nil case *AssignmentNode: - //s.pushExpression(d.Name, d.Expression) s.cs = s.cs.add(d.Name, d.Expression, s.fs) return nil default: @@ -111,23 +108,10 @@ func (s *evaluationScope) declare(n Node) error { } } -//func (s *evaluationScope) pushExpression(id string, n Node) { -// s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, expression: n, size: len(s.cs[len(s.cs)-1])}) -//} - -//func (s *evaluationScope) pushExpression2(id string, n Node, ctx evaluationCtx) evaluationCtx { -// -//} - func (s *evaluationScope) pushValue(id string, v rideType) { - //s.cs[len(s.cs)-1] = append(s.cs[len(s.cs)-1], esValue{id: id, value: v}) s.cs = s.cs.addValue(id, v, s.fs) } -//func (s *evaluationScope) popValue() { -// s.cs[len(s.cs)-1] = s.cs[len(s.cs)-1][:len(s.cs[len(s.cs)-1])-1] -//} - func (s *evaluationScope) constant(id string) (rideType, bool) { if c, ok := s.constants[id]; ok { if c.value == nil { @@ -140,54 +124,6 @@ func (s *evaluationScope) constant(id string) (rideType, bool) { return nil, false } -//func lookup(s []esValue, id string) (esValue, bool) { -// for i := len(s) - 1; i >= 0; i-- { -// if v := s[i]; v.id == id { -// return v, true -// } -// } -// return esValue{}, false -//} - -//func (s *evaluationScope) value(id string) (esValue, bool) { -//if p := len(s.cs) - 1; p >= 0 { -// v, ok := lookup(s.cs[p], id) -// if ok { -// return v, true -// } -//} -//for i := s.cl - 1; i >= 0; i-- { -// v, ok := lookup(s.cs[i], id) -// if ok { -// return v, true -// } -//} -//return esValue{}, false -//} - -//func (s *evaluationScope) pushUserFunction(uf *FunctionDeclarationNode) { -// s.user = append(s.user, esFunction{fn: uf, sp: len(s.cs)}) -//} - -//func (s *evaluationScope) popUserFunction() error { -// l := len(s.user) -// if l == 0 { -// return errors.New("empty user functions scope") -// } -// s.user = s.user[:l-1] -// return nil -//} - -//func (s *evaluationScope) userFunction(id string) (*FunctionDeclarationNode, int, error) { -// for i := len(s.user) - 1; i >= 0; i-- { -// uf := s.user[i] -// if uf.fn.Name == id { -// return uf.fn, uf.sp, nil -// } -// } -// return nil, 0, errors.Errorf("user function '%s' is not found", id) -//} - func newEvaluationScope(v int, env RideEnvironment) (evaluationScope, error) { constants, err := selectConstantNames(v) if err != nil { @@ -232,10 +168,9 @@ func newEvaluationScope(v int, env RideEnvironment) (evaluationScope, error) { return evaluationScope{ constants: cs, system: fs, - //cs: //[][]esValue{make([]esValue, 0)}, - cs: newVarsCtx(), - fs: newFuncCtx(), - env: env, + cs: newVarsCtx(), + fs: newFuncCtx(), + env: env, }, nil } @@ -374,9 +309,7 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT case *ReferenceNode: id := n.Name - //v, ok := e.s.value(varsCtx, id) v := varsCtx.get(id) - //ok := v != nil if v == nil { if v, ok := e.s.constant(id); ok { return v, nil @@ -394,7 +327,6 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT if isThrow(r) { return r, nil } - //e.s.pushValue(id, r) v.value = r return r, nil } @@ -402,7 +334,6 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT case *FunctionDeclarationNode: id := n.Name - //e.s.pushUserFunction(n) r, err := e.walk(n.Block, varsCtx, funcCtx.add(id, n, varsCtx)) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate block after declaration of function '%s'", id) @@ -410,10 +341,6 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT if isThrow(r) { return r, nil } - //err = e.s.popUserFunction() - //if err != nil { - // return nil, errors.Wrapf(err, "failed to evaluate declaration of function '%s'", id) - //} return r, nil case *FunctionCallNode: @@ -442,7 +369,6 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT } return r, nil } - //uf, _, err := e.s.userFunction(id) uf := funcCtx.get(id) if uf == nil { return nil, errors.Errorf("failed to call function '%s'", id) @@ -464,18 +390,11 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT args[i] = esValue{id: an, value: av} localVars = localVars.addValue(an, av, funcCtx) } - //e.s.cs = append(e.s.cs, make([]esValue, len(args))) - //e.s.cs = append(e.s.cs, args) - //for i, arg := range args { - // e.s.cs[len(e.s.cs)-1][i] = arg - //} var tmp int - //tmp, e.s.cl = e.s.cl, cl r, err := e.walk(uf.fn.Body, localVars, funcCtx) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate function '%s' body", id) } - //e.s.cs = e.s.cs[:len(e.s.cs)-1] e.s.cl = tmp return r, nil From 2c1c208f9434dcdbf1a852c0722ae801c09776fe Mon Sep 17 00:00:00 2001 From: frozen Date: Fri, 19 Mar 2021 13:44:11 +0300 Subject: [PATCH 50/55] Fix small errors. --- pkg/ride/tree_evaluation.go | 4 ++-- pkg/ride/tree_evaluator.go | 2 -- pkg/ride/tree_expand_test.go | 7 ++----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index f63938900d..b8be9443b3 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -25,7 +25,7 @@ func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) //if err != nil { // return nil, errors.Wrap(err, "vm verifier") //} - r2, err := CallTreeVerifier(env, MustExpand(tree)) + r2, err := CallTreeVerifier(env, tree) if err != nil { return nil, errors.Wrap(err, "tree verifier") } @@ -69,7 +69,7 @@ func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, } func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - rs1, err := CallTreeFunction(txID, env, MustExpand(tree), name, args) + rs1, err := CallTreeFunction(txID, env, tree, name, args) if err != nil { return nil, errors.Wrap(err, "call function by tree") } diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index d3f268a496..2352a1da06 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -296,7 +296,6 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT case *AssignmentNode: id := n.Name - //e.s.pushExpression(id, n.Expression) r, err := e.walk(n.Block, varsCtx.add(id, n.Expression, funcCtx), funcCtx) if err != nil { return nil, errors.Wrapf(err, "failed to evaluate block after declaration of variable '%s'", id) @@ -304,7 +303,6 @@ func (e *treeEvaluator) walk(node Node, varsCtx varsCtx, funcCtx funcCtx) (rideT if isThrow(r) { return r, nil } - //e.s.popValue() return r, nil case *ReferenceNode: diff --git a/pkg/ride/tree_expand_test.go b/pkg/ride/tree_expand_test.go index a88f4b02b1..3a3ebcfb78 100644 --- a/pkg/ride/tree_expand_test.go +++ b/pkg/ride/tree_expand_test.go @@ -154,7 +154,7 @@ func TestTreeExpand11(t *testing.T) { require.NoError(t, err) require.Equal(t, true, rs.Result()) }) - t.Run("expand 2 funcs", func(t *testing.T) { + t.Run("expand 2 functions", func(t *testing.T) { /** {-# STDLIB_VERSION 3 #-} {-# SCRIPT_TYPE ACCOUNT #-} @@ -183,9 +183,6 @@ func TestTreeExpand11(t *testing.T) { require.Equal(t, true, rs.Result()) }) - t.Run("", func(t *testing.T) { - - }) } /** @@ -221,7 +218,7 @@ func TestExpandScope(t *testing.T) { require.NotNil(t, m.get1("call")) } -func TestExpandSmthWrote(t *testing.T) { +func TestExpand(t *testing.T) { source := `AAIDAAAAAAAAAAQIARIAAAAAAwEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABAAAAA2tleQMJAAAAAAAAAgUAAAADa2V5AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAEmdldFByaWNlSGlzdG9yeUtleQAAAAEAAAAFYmxvY2sJAAEsAAAAAgIAAAAGcHJpY2VfCQABpAAAAAEFAAAABWJsb2NrAQAAAA9nZXRQcmljZUhpc3RvcnkAAAABAAAABmhlaWdodAkBAAAADmdldE51bWJlckJ5S2V5AAAAAQkBAAAAEmdldFByaWNlSGlzdG9yeUtleQAAAAEFAAAABmhlaWdodAAAAAEAAAABaQEAAAAUZmluYWxpemVDdXJyZW50UHJpY2UAAAAAAwkBAAAAAiE9AAAAAgkBAAAAD2dldFByaWNlSGlzdG9yeQAAAAEFAAAABmhlaWdodAAAAAAAAAAAAAkAAAIAAAABAgAAAA93YWl0IG5leHQgYmxvY2sJAQAAAAhXcml0ZVNldAAAAAEFAAAAA25pbAAAAACFlzmA` src, err := base64.StdEncoding.DecodeString(source) From f86c9819976410cebd2f21453353115251b0b287 Mon Sep 17 00:00:00 2001 From: frozen Date: Mon, 22 Mar 2021 18:01:40 +0300 Subject: [PATCH 51/55] Clean up compiler. --- pkg/ride/compiler.go | 12 +++--- pkg/ride/compiler_assigment.go | 20 ++++----- pkg/ride/compiler_call_system.go | 22 ++++------ pkg/ride/compiler_call_user.go | 5 +-- pkg/ride/compiler_conditional.go | 58 +++++++------------------- pkg/ride/compiler_func.go | 2 +- pkg/ride/compiler_main.go | 2 +- pkg/ride/compiler_test.go | 40 ------------------ pkg/ride/vm_estimator.go | 1 - pkg/ride/vm_test.go | 71 -------------------------------- 10 files changed, 39 insertions(+), 194 deletions(-) diff --git a/pkg/ride/compiler.go b/pkg/ride/compiler.go index 08b74df28f..bb750e10a8 100644 --- a/pkg/ride/compiler.go +++ b/pkg/ride/compiler.go @@ -20,11 +20,11 @@ func encode(v uint16) []byte { func compile(f State, node Node) (State, error) { switch n := node.(type) { case *AssignmentNode: - fsm, err := compile(f.Assigment(n.Name), n.Expression) + state, err := compile(f.Assigment(n.Name), n.Expression) if err != nil { - return fsm, err + return state, err } - return compile(fsm.Return(), n.Block) + return compile(state.Return(), n.Block) case *LongNode: return f.Long(n.Value), nil case *FunctionCallNode: @@ -60,11 +60,11 @@ func compile(f State, node Node) (State, error) { } return f.Return(), nil case *FunctionDeclarationNode: - fsm, err := compile(f.Func(n.Name, n.Arguments, n.invocationParameter), n.Body) + state, err := compile(f.Func(n.Name, n.Arguments, n.invocationParameter), n.Body) if err != nil { - return fsm, err + return state, err } - return compile(fsm.Return(), n.Block) + return compile(state.Return(), n.Block) case *PropertyNode: f, err := compile(f.Property(n.Name), n.Object) if err != nil { diff --git a/pkg/ride/compiler_assigment.go b/pkg/ride/compiler_assigment.go index 6365c0b39d..132e6da606 100644 --- a/pkg/ride/compiler_assigment.go +++ b/pkg/ride/compiler_assigment.go @@ -8,12 +8,9 @@ type AssigmentState struct { bodyParams params prev State name string - // ref id - n uniqueid - - // Clean internal assigments. - body Deferred - d Deferreds + n uniqueid + body Deferred + d Deferreds } func (a AssigmentState) backward(state State) State { @@ -56,8 +53,8 @@ func (a AssigmentState) Boolean(v bool) State { return a } -func assigmentFsmTransition(prev State, params params, name string, n uniqueid, d Deferreds) State { - return newAssigmentFsm(prev, params, name, n, d) +func assigmentTransition(prev State, params params, name string, n uniqueid, d Deferreds) State { + return newAssigment(prev, params, name, n, d) } func extendParams(p params) params { @@ -65,7 +62,7 @@ func extendParams(p params) params { return p } -func newAssigmentFsm(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, @@ -78,11 +75,8 @@ func newAssigmentFsm(prev State, p params, name string, n uniqueid, d Deferreds) // Create new scope, so assigment in assigment can't affect global state. func (a AssigmentState) Assigment(name string) State { - //params := a.params - //params.r = newReferences(params.r) - // TODO clear var in var n := a.params.u.next() - return assigmentFsmTransition(a, a.bodyParams, name, n, a.d) + return assigmentTransition(a, a.bodyParams, name, n, a.d) } func (a AssigmentState) Return() State { diff --git a/pkg/ride/compiler_call_system.go b/pkg/ride/compiler_call_system.go index e22816b3e0..1b66691c8d 100644 --- a/pkg/ride/compiler_call_system.go +++ b/pkg/ride/compiler_call_system.go @@ -6,13 +6,8 @@ import "fmt" type CallSystemState struct { prev State params - name string - argc uint16 - // positions of arguments - //argn []uint16 - // Position where we started write code for current state. - startedAt uint16 - //retAssig uint16 + name string + argc uint16 deferred []Deferred deferreds Deferreds // Sequential function arguments. @@ -42,11 +37,11 @@ func (a CallSystemState) Condition() State { } func (a CallSystemState) TrueBranch() State { - panic("Illegal call `TrueBranch` on CallFsm") + panic("Illegal call `TrueBranch` on CallSystemState") } func (a CallSystemState) FalseBranch() State { - panic("Illegal call `FalseBranch` on CallFsm") + panic("Illegal call `FalseBranch` on CallSystemState") } func (a CallSystemState) String(value string) State { @@ -61,12 +56,12 @@ func (a CallSystemState) Boolean(value bool) State { func callTransition(prev State, params params, name string, argc uint16, d Deferreds) State { if _, ok := params.r.getFunc(name); ok { - return newCallUserFsm(prev, params, name, argc, d) + return newCallUserState(prev, params, name, argc, d) } - return newCallSystemFsm(prev, params, name, argc, d) + return newCallSystemState(prev, params, name, argc, d) } -func newCallSystemFsm(prev State, params params, name string, argc uint16, d Deferreds) State { +func newCallSystemState(prev State, params params, name string, argc uint16, d Deferreds) State { var ns []uniqueid for i := uint16(0); i < argc; i++ { ns = append(ns, params.u.next()) @@ -77,7 +72,6 @@ func newCallSystemFsm(prev State, params params, name string, argc uint16, d Def params: params, name: name, argc: argc, - startedAt: params.b.len(), deferreds: d, ns: ns, } @@ -85,7 +79,7 @@ func newCallSystemFsm(prev State, params params, name string, argc uint16, d Def func (a CallSystemState) Assigment(name string) State { n := a.params.u.next() - return assigmentFsmTransition(a, a.params, name, n, a.deferreds) + return assigmentTransition(a, a.params, name, n, a.deferreds) } func (a CallSystemState) Long(value int64) State { diff --git a/pkg/ride/compiler_call_user.go b/pkg/ride/compiler_call_user.go index aec74aeff1..a95647c113 100644 --- a/pkg/ride/compiler_call_user.go +++ b/pkg/ride/compiler_call_user.go @@ -8,8 +8,6 @@ type CallUserState struct { params name string argc uint16 - startedAt uint16 - deferreds Deferreds ns []uniqueid } @@ -22,13 +20,12 @@ func (a CallUserState) backward(state State) State { return a } -func newCallUserFsm(prev State, params params, name string, argc uint16, d Deferreds) State { +func newCallUserState(prev State, params params, name string, argc uint16, d Deferreds) State { return &CallUserState{ prev: prev, params: params, name: name, argc: argc, - startedAt: params.b.len(), deferreds: d, } } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index 2ab2d7f1ac..c6aff4cd54 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -2,15 +2,11 @@ package ride import "fmt" -//import "fmt" - // If-else statement. type ConditionalState struct { - params - prev State /* - Offset where true branch starts execution. - We need this because code can look like: + Be aware that `x` and `y` should not be executed. + if (true) then { let x = throw() 5 @@ -18,16 +14,12 @@ type ConditionalState struct { let y = throw() 6 } - - `X` and `y` should not be executed. */ - patchTruePosition uint16 - // Same as true position. - patchFalsePosition uint16 - // Offset where `if` code block ends. - patchNextPosition uint16 - startedAt uint16 - rets []uint16 + + params + prev State + + rets []uint16 // Clean assigments after exit. deferred []Deferred @@ -51,7 +43,6 @@ func (a ConditionalState) Property(name string) State { } func (a ConditionalState) Func(name string, args []string, invoke string) State { - //panic(fmt.Sprintf("Illegal call Func on ConditionalState %s", a.txID)) return funcTransition(a, a.params, name, args, invoke) } @@ -64,8 +55,6 @@ func conditionalTransition(prev State, params params, deferreds Deferreds) State return ConditionalState{ prev: prev, params: params, - startedAt: params.b.len(), - //deferred: make([[]Deferred, 3), deferreds: deferreds, } } @@ -85,9 +74,8 @@ func (a ConditionalState) FalseBranch() State { func (a ConditionalState) Assigment(name string) State { n := a.params.u.next() - //a.assigments = append(a.assigments, n) a.r.setAssigment(name, n) - return assigmentFsmTransition(a, a.params, name, n, a.deferreds) + return assigmentTransition(a, a.params, name, n, a.deferreds) } func (a ConditionalState) Long(value int64) State { @@ -128,7 +116,6 @@ func (a ConditionalState) Write(_ params, _ []byte) { panic("len(a.deferred) != 3") } - //condB := a.deferred[0] trueB := a.deferred[1] falsB := a.deferred[2] @@ -136,34 +123,19 @@ func (a ConditionalState) Write(_ params, _ []byte) { a.b.write(encode(a.condN)) a.b.jpmIfFalse() - a.patchTruePosition = a.b.writeStub(2) - //a.b.write(encode(a.b.len())) - a.patchFalsePosition = a.b.writeStub(2) - a.patchNextPosition = a.b.writeStub(2) - - a.b.patch(a.patchTruePosition, encode(a.b.len())) - //writeDeferred(a.params, trueB) - //a.b.ret() + patchTruePosition := a.b.writeStub(2) + patchFalsePosition := a.b.writeStub(2) + patchNextPosition := a.b.writeStub(2) + + a.b.patch(patchTruePosition, encode(a.b.len())) trueB.Write(a.params, nil) a.b.ret() - a.b.patch(a.patchFalsePosition, encode(a.b.len())) + a.b.patch(patchFalsePosition, encode(a.b.len())) falsB.Write(a.params, nil) a.b.ret() - //for _, v := range condB[1:] { - // v.Write(a.params) - //} - - a.b.patch(a.patchNextPosition, encode(a.b.len())) - //for _, v := range condB[1:] { - // v.Clean() - //} - //a.b.write(b) - //a.b.ret() - - //writeDeferred(a.params, a.deferred) + a.b.patch(patchNextPosition, encode(a.b.len())) } func (a ConditionalState) Clean() { - //panic("ConditionalState Clean") } diff --git a/pkg/ride/compiler_func.go b/pkg/ride/compiler_func.go index 61f2bd8c35..7c7814cea6 100644 --- a/pkg/ride/compiler_func.go +++ b/pkg/ride/compiler_func.go @@ -96,7 +96,7 @@ func funcTransition(prev State, params params, name string, args []string, invok func (a FuncState) Assigment(name string) State { n := a.params.u.next() - return assigmentFsmTransition(a, a.params, name, n, a.defers) + return assigmentTransition(a, a.params, name, n, a.defers) } func (a FuncState) ParamIds() []uniqueid { diff --git a/pkg/ride/compiler_main.go b/pkg/ride/compiler_main.go index a457222d75..cd93d4deee 100644 --- a/pkg/ride/compiler_main.go +++ b/pkg/ride/compiler_main.go @@ -56,7 +56,7 @@ func NewMain(params params) State { func (a MainState) Assigment(name string) State { n := a.params.u.next() - return assigmentFsmTransition(a, a.params, name, n, a.deferreds) + return assigmentTransition(a, a.params, name, n, a.deferreds) } func (a MainState) Return() State { diff --git a/pkg/ride/compiler_test.go b/pkg/ride/compiler_test.go index 3099599605..43466b0601 100644 --- a/pkg/ride/compiler_test.go +++ b/pkg/ride/compiler_test.go @@ -685,46 +685,10 @@ func TestNoDuplicateCallToState(t *testing.T) { for _, c := range rs.Calls() { t.Log(c) } - //t.Log(rs.Calls()) require.NoError(t, err) - - //t.Log(rs.Calls()) require.False(t, rs.Result()) } -//type points struct { -// value []point `cbor:"0,keyasint"` -//} - -//func TestSerialize(t *testing.T) { -// -// //m := points{ -// // value: []point{ -// // {value: rideBoolean(true)}, -// // {value: rideInt(5), constant: true}, -// // }, -// //} -// m := point{ -// position: 43, -// value: rideUnit{}, -// fn: nil, -// constant: true, -// debugInfo: "bla", -// } -// -// rs, err := cbor.Marshal(m) -// require.NoError(t, err) -// -// t.Log(rs) -// -// var m2 point -// -// err = cbor.Unmarshal(rs, &m2) -// require.NoError(t, err) -// t.Log(m2) -// -//} - /* {-# STDLIB_VERSION 3 #-} {-# SCRIPT_TYPE ACCOUNT #-} @@ -1478,10 +1442,6 @@ func Test111111(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) - //rs, err := CallTreeVerifier(env, tree) - //for i, c := range rs.Calls() { - // t.Log(i, " ", c) - //} exe, err := CompileTree("", tree) require.NoError(t, err) diff --git a/pkg/ride/vm_estimator.go b/pkg/ride/vm_estimator.go index 744c4a2370..bd42f5b3ac 100644 --- a/pkg/ride/vm_estimator.go +++ b/pkg/ride/vm_estimator.go @@ -1,7 +1,6 @@ package ride type VmEstimator struct { - //cost int builtin map[string]int } diff --git a/pkg/ride/vm_test.go b/pkg/ride/vm_test.go index 5425ddb878..f0849ce25f 100644 --- a/pkg/ride/vm_test.go +++ b/pkg/ride/vm_test.go @@ -12,77 +12,6 @@ import ( //go:generate moq -pkg ride -out types_moq_test.go ../types SmartState:MockSmartState -/* -func TestExecution(t *testing.T) { - //state := &MockSmartState{NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) { - // return testTransferWithProofs(), nil - //}} - //env := &MockRideEnvironment{ - // transactionFunc: testTransferObject, - // stateFunc: func() types.SmartState { - // return state - // }, - // schemeFunc: func() byte { - // return 'T' - // }, - //} - for _, test := range []struct { - comment string - source string - env RideEnvironment - res bool - }{ - //{`V1: true`, "AQa3b8tH", nil, true}, - //{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", nil, true}, - //{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true}, - //{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", nil, false}, - //{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true}, - //{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", nil, true}, - //{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", nil, false}, - //{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", nil, true}, - {`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true}, - //{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true}, - //{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true}, - //{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true}, - //{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true}, - //{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true}, - //{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true}, - //{`false`, `AQfeYll6`, nil, false}, - //{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true}, - //{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, nil, true}, - //{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false}, - //{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true}, - //{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true}, - //{`tx.proofs[0] != base58'' && tx.proofs[1] == base58''`, `BAMJAQAAAAIhPQAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAEAAAAACQAAAAAAAAIJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQEAAAAAB106gzM=`, env, true}, - //{`match tx {case t : TransferTransaction | MassTransferTransaction | ExchangeTransaction => true; case _ => false}`, `AQQAAAAHJG1hdGNoMAUAAAACdHgDAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAABNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAXTWFzc1RyYW5zZmVyVHJhbnNhY3Rpb24GCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAE1RyYW5zZmVyVHJhbnNhY3Rpb24EAAAAAXQFAAAAByRtYXRjaDAGB6Ilvok=`, env, true}, - //{`V2: match transactionById(tx.id) {case t: Unit => false case _ => true}`, `AgQAAAAHJG1hdGNoMAkAA+gAAAABCAUAAAACdHgAAAACaWQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQEAAAAAXQFAAAAByRtYXRjaDAHBp9TFcQ=`, env, true}, - //{`Up() == UP`, `AwkAAAAAAAACCQEAAAACVXAAAAAABQAAAAJVUPGUxeg=`, nil, true}, - //{`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==`, nil, true}, - //{`Unit() == unit`, `AwkAAAAAAAACCQEAAAAEVW5pdAAAAAAFAAAABHVuaXTstg1G`, nil, true}, - } { - src, err := base64.StdEncoding.DecodeString(test.source) - require.NoError(t, err, test.comment) - - tree, err := Parse(src) - require.NoError(t, err, test.comment) - assert.NotNil(t, tree, test.comment) - - script, err := Compile(tree) - require.NoError(t, err, test.comment) - assert.NotNil(t, script, test.comment) - - res, err := script.Run(test.env) - require.NoError(t, err, test.comment) - assert.NotNil(t, res, test.comment) - r, ok := res.(ScriptResult) - assert.True(t, ok, test.comment) - assert.Equal(t, test.res, r.Result(), test.comment) - } -} -*/ func newTransferTransaction() *proto.TransferWithProofs { js := `{"type":4,"version":2,"id":"CqjGMbrd5bFmLAv2mUSdphEJSgVWkWa6ZtcMkKmgH2ax","proofs":["5W7hjPpgmmhxevCt4A7y9F8oNJ4V9w2g8jhQgx2qGmBTNsP1p1MpQeKF3cvZULwJ7vQthZfSx2BhL6TWkHSVLzvq"],"senderPublicKey":"14ovLL9a6xbBfftyxGNLKMdbnzGgnaFQjmgUJGdho6nY","assetId":null,"feeAssetId":null,"timestamp":1544715621,"amount":15,"fee":10000,"recipient":"3P2USE3iYK5w7jNahAUHTytNbVRccGZwQH3"}` tv2 := &proto.TransferWithProofs{} From 1d6f34acedfbbd9156fbf7a0d97b3b1a22e8ade6 Mon Sep 17 00:00:00 2001 From: frozen Date: Thu, 25 Mar 2021 16:25:17 +0300 Subject: [PATCH 52/55] Fix bug with var override in condition stste. --- pkg/ride/compiler_conditional.go | 1 - pkg/ride/compiler_test.go | 35 +++++++++++++++++++++++++++++++- pkg/ride/runtime.go | 16 +++++++++++++++ pkg/state/api.go | 3 +++ pkg/state/state.go | 5 +++++ pkg/state/threadsafe_wrapper.go | 5 +++++ 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index c6aff4cd54..ad29877615 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -74,7 +74,6 @@ func (a ConditionalState) FalseBranch() State { func (a ConditionalState) Assigment(name string) State { n := a.params.u.next() - a.r.setAssigment(name, n) return assigmentTransition(a, a.params, name, n, a.deferreds) } diff --git a/pkg/ride/compiler_test.go b/pkg/ride/compiler_test.go index 43466b0601..7c4d627fcb 100644 --- a/pkg/ride/compiler_test.go +++ b/pkg/ride/compiler_test.go @@ -49,7 +49,7 @@ var defaultEnv = &MockRideEnvironment{ }, } -func Test22(t *testing.T) { +func TestCompiler(t *testing.T) { env := defaultEnv for _, test := range []struct { comment string @@ -1474,3 +1474,36 @@ func TestShadowedVariable(t *testing.T) { require.NoError(t, err) 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) { + source := `AwQAAAAJcHJldk9yZGVyBwoBAAAACGludGVybmFsAAAAAQAAAAlwcmV2T3JkZXIDBQAAAAlwcmV2T3JkZXIHBgMHBwkBAAAACGludGVybmFsAAAAAQUAAAAJcHJldk9yZGVyxqI+QQ==` + + 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) + script, err := CompileTree("", tree) + require.NoError(t, err) + + rs, err := script.Verify(defaultEnv) + require.NoError(t, err) + require.Equal(t, true, rs.Result()) +} diff --git a/pkg/ride/runtime.go b/pkg/ride/runtime.go index 42764a97d5..d71d0f5247 100644 --- a/pkg/ride/runtime.go +++ b/pkg/ride/runtime.go @@ -17,6 +17,10 @@ type rideType interface { Serialize(Serializer) error } +func RideTypes(types ...rideType) []rideType { + return types +} + type rideThrow string func (a rideThrow) Serialize(serializer Serializer) error { @@ -45,6 +49,10 @@ func (a rideThrow) get(prop string) (rideType, error) { type rideBoolean bool +func RideBoolean(b bool) rideBoolean { + return rideBoolean(b) +} + func (b rideBoolean) Serialize(serializer Serializer) error { return serializer.RideBool(b) } @@ -66,6 +74,10 @@ func (b rideBoolean) get(prop string) (rideType, error) { type rideInt int64 +func RideInt(i int64) rideInt { + return rideInt(i) +} + func (l rideInt) Serialize(serializer Serializer) error { return serializer.RideInt(l) } @@ -87,6 +99,10 @@ func (l rideInt) get(prop string) (rideType, error) { type rideString string +func RideString(s string) rideString { + return rideString(s) +} + func (s rideString) Serialize(serializer Serializer) error { return serializer.RideString(s) } diff --git a/pkg/state/api.go b/pkg/state/api.go index 3cf0653275..7c9305034b 100644 --- a/pkg/state/api.go +++ b/pkg/state/api.go @@ -127,6 +127,9 @@ type StateInfo interface { // ShouldPersisAddressTransactions checks if PersisAddressTransactions // should be called. ShouldPersistAddressTransactions() (bool, error) + + // Method should be used only in tests. + SmartState() types.SmartState } // StateModifier contains all the methods needed to modify node's state. diff --git a/pkg/state/state.go b/pkg/state/state.go index e9ca0a9e55..6bf1fa2ac4 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "fmt" + "github.com/wavesplatform/gowaves/pkg/types" "math/big" "os" "path/filepath" @@ -354,6 +355,10 @@ type stateManager struct { newBlocks *newBlocks } +func (s *stateManager) SmartState() types.SmartState { + return s +} + func newStateManager(dataDir string, params StateParams, settings *settings.BlockchainSettings) (*stateManager, error) { err := validateSettings(settings) if err != nil { diff --git a/pkg/state/threadsafe_wrapper.go b/pkg/state/threadsafe_wrapper.go index 0fd4cffd15..cf22386b9d 100644 --- a/pkg/state/threadsafe_wrapper.go +++ b/pkg/state/threadsafe_wrapper.go @@ -1,6 +1,7 @@ package state import ( + "github.com/wavesplatform/gowaves/pkg/types" "math/big" "sync" "sync/atomic" @@ -21,6 +22,10 @@ func (a *ThreadSafeReadWrapper) HitSourceAtHeight(height proto.Height) ([]byte, return a.s.HitSourceAtHeight(height) } +func (a *ThreadSafeReadWrapper) SmartState() types.SmartState { + return a.s.SmartState() +} + func (a *ThreadSafeReadWrapper) MapR(f func(StateInfo) (interface{}, error)) (interface{}, error) { a.mu.RLock() defer a.mu.RUnlock() From a644a73c6dbfcda99a7bc9b0ccdf01a4cd42f744 Mon Sep 17 00:00:00 2001 From: frozen Date: Fri, 2 Apr 2021 14:15:42 +0300 Subject: [PATCH 53/55] Fix bug with nil values and duplicate vars in conditional state. --- pkg/ride/compiler.go | 1 + pkg/ride/compiler_conditional.go | 10 +++-- pkg/ride/compiler_test.go | 7 ++- pkg/ride/functions_predefined.go | 5 +-- pkg/ride/tree.go | 10 +++++ pkg/ride/tree_evaluation.go | 76 +++++++++++++++++--------------- pkg/ride/tree_evaluator.go | 11 +++-- pkg/ride/tree_expand_test.go | 24 ++-------- 8 files changed, 76 insertions(+), 68 deletions(-) diff --git a/pkg/ride/compiler.go b/pkg/ride/compiler.go index bb750e10a8..97daf4b71d 100644 --- a/pkg/ride/compiler.go +++ b/pkg/ride/compiler.go @@ -147,6 +147,7 @@ func compileFunction(txID string, libVersion int, nodes []Node, isDapp bool, has } func CompileTree(tx string, tree *Tree) (*Executable, error) { + tree = MustExpand(tree) if tree.IsDApp() { return CompileDapp(tx, tree) } diff --git a/pkg/ride/compiler_conditional.go b/pkg/ride/compiler_conditional.go index ad29877615..7d44d02b17 100644 --- a/pkg/ride/compiler_conditional.go +++ b/pkg/ride/compiler_conditional.go @@ -16,6 +16,7 @@ type ConditionalState struct { } */ + originalParams params params prev State @@ -53,9 +54,10 @@ func (a ConditionalState) Bytes(value []byte) State { func conditionalTransition(prev State, params params, deferreds Deferreds) State { return ConditionalState{ - prev: prev, - params: params, - deferreds: deferreds, + prev: prev, + params: extendParams(params), + deferreds: deferreds, + originalParams: params, } } @@ -65,10 +67,12 @@ func (a ConditionalState) Condition() State { } func (a ConditionalState) TrueBranch() State { + a.params = extendParams(a.originalParams) return a } func (a ConditionalState) FalseBranch() State { + a.params = extendParams(a.originalParams) return a } diff --git a/pkg/ride/compiler_test.go b/pkg/ride/compiler_test.go index 7c4d627fcb..738df55ace 100644 --- a/pkg/ride/compiler_test.go +++ b/pkg/ride/compiler_test.go @@ -110,7 +110,12 @@ func TestCompiler(t *testing.T) { require.NoError(t, err, test.comment) assert.NotNil(t, tree, test.comment) + tree = MustExpand(tree) + script, err := CompileTree("", tree) + + require.True(t, tree.Expanded) + require.NoError(t, err, test.comment) assert.NotNil(t, script, test.comment) @@ -1465,7 +1470,7 @@ func TestShadowedVariable(t *testing.T) { tree, err := Parse(src) require.NoError(t, err) tree = MustExpand(tree) - require.Equal(t, "(let height = { height }; height != 0)", DecompileTree(tree)) + require.Equal(t, "(let height$getPriceHistory = { height }; height$getPriceHistory != 0)", DecompileTree(tree)) script, err := CompileTree("", tree) require.NoError(t, err) diff --git a/pkg/ride/functions_predefined.go b/pkg/ride/functions_predefined.go index d4996f5780..2d4f6f1e64 100644 --- a/pkg/ride/functions_predefined.go +++ b/pkg/ride/functions_predefined.go @@ -2,15 +2,14 @@ package ride import ( "math" - //"github.com/pkg/errors" ) func tx(env RideEnvironment, _ ...rideType) (rideType, error) { - return env.transaction(), nil + return newTx(env), nil } func this(env RideEnvironment, _ ...rideType) (rideType, error) { - return env.this(), nil + return newThis(env), nil } func height(env RideEnvironment, _ ...rideType) (rideType, error) { diff --git a/pkg/ride/tree.go b/pkg/ride/tree.go index da818d0afc..6778ebeb7c 100644 --- a/pkg/ride/tree.go +++ b/pkg/ride/tree.go @@ -1,5 +1,7 @@ package ride +import "github.com/pkg/errors" + type Node interface { node() SetBlock(node Node) @@ -294,3 +296,11 @@ func (t *Tree) HasVerifier() bool { func (t *Tree) IsDApp() bool { return t.AppVersion != scriptApplicationVersion } + +func (t *Tree) Invoke(env RideEnvironment, name string, arguments []rideType) (RideResult, error) { + e, err := treeFunctionEvaluator(env, t, name, arguments) + if err != nil { + return nil, errors.Wrapf(err, "failed to call function '%s'", name) + } + return e.evaluate() +} diff --git a/pkg/ride/tree_evaluation.go b/pkg/ride/tree_evaluation.go index b8be9443b3..170a06cb08 100644 --- a/pkg/ride/tree_evaluation.go +++ b/pkg/ride/tree_evaluation.go @@ -2,7 +2,9 @@ package ride import ( "github.com/pkg/errors" + "github.com/stretchr/testify/assert" "github.com/wavesplatform/gowaves/pkg/proto" + "go.uber.org/zap" ) func CallTreeVerifier(env RideEnvironment, tree *Tree) (RideResult, error) { @@ -21,47 +23,51 @@ func CallVmVerifier(txID string, env RideEnvironment, compiled *Executable) (Rid } func CallVerifier(txID string, env RideEnvironment, tree *Tree, exe *Executable) (RideResult, error) { - //r, err := CallVmVerifier(txID, env, exe) - //if err != nil { - // return nil, errors.Wrap(err, "vm verifier") - //} - r2, err := CallTreeVerifier(env, tree) + tree = MustExpand(tree) + r1, err := CallTreeVerifier(env, tree) if err != nil { return nil, errors.Wrap(err, "tree verifier") } - // - //if !r.Eq(r2) { - // c1 := r.Calls() - // c2 := r2.Calls() - // max := len(c1) - // if len(c2) > len(c1) { - // max = len(c2) - // } - // for i := 0; i < max; i++ { - // //zap.S().Error("R1 != R2: failed to call account script on transaction ") - // if i <= len(c1)-1 { - // zap.S().Error(i, txID, " ", c1[i]) - // } else { - // zap.S().Error(i, txID, " ", "") - // } - // if i <= len(c2)-1 { - // zap.S().Error(i, txID, " ", c2[i]) - // } else { - // zap.S().Error(i, txID, " ", "") - // } - // } - // - // return nil, errors.New("R1 != R2: failed to call account script on transaction ") - //} + r2, err := CallVmVerifier(txID, env, exe) + if err != nil { + return nil, errors.Wrap(err, "vm verifier") + } + if !r1.Eq(r2) { + c1 := r1.Calls() + c2 := r2.Calls() + max := len(c1) + if len(c2) > len(c1) { + max = len(c2) + } + for i := 0; i < max; i++ { + //zap.S().Error("R1 != R2: failed to call account script on transaction ") + if i <= len(c1)-1 { + zap.S().Error(i, txID, " ", c1[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + if i <= len(c2)-1 { + zap.S().Error(i, txID, " ", c2[i]) + } else { + zap.S().Error(i, txID, " ", "") + } + } + return nil, errors.New("R1 != R2: failed to call account script on transaction ") + } return r2, nil } func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, args proto.Arguments) (RideResult, error) { - if name == "" { - name = "default" + var types []rideType + for _, arg := range args { + a, err := convertArgument(arg) + if err != nil { + return nil, errors.Wrapf(err, "failed to call function '%s'", name) + } + types = append(types, a) } - e, err := treeFunctionEvaluator(env, tree, name, args) + e, err := treeFunctionEvaluator(env, tree, name, types) if err != nil { return nil, errors.Wrapf(err, "failed to call function '%s'", name) } @@ -69,12 +75,12 @@ func CallTreeFunction(txID string, env RideEnvironment, tree *Tree, name string, } func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, name string, args proto.Arguments) (RideResult, error) { + tree = MustExpand(tree) rs1, err := CallTreeFunction(txID, env, tree, name, args) if err != nil { return nil, errors.Wrap(err, "call function by tree") } - return rs1, nil - /* * + /* */ rs2, err := CallVmFunction(txID, env, exe, name, args) if err != nil { return rs2, errors.Wrap(err, "call function by vm") @@ -111,8 +117,8 @@ func CallFunction(txID string, env RideEnvironment, exe *Executable, tree *Tree, return nil, errors.New("R1 != R2: failed to call account script on transaction ") } - return rs2, nil /* */ + return rs1, nil } func CallVmFunction(txID string, env RideEnvironment, e *Executable, name string, args proto.Arguments) (RideResult, error) { diff --git a/pkg/ride/tree_evaluator.go b/pkg/ride/tree_evaluator.go index 2352a1da06..9a0072afcb 100644 --- a/pkg/ride/tree_evaluator.go +++ b/pkg/ride/tree_evaluator.go @@ -452,7 +452,10 @@ func treeVerifierEvaluator(env RideEnvironment, tree *Tree) (*treeEvaluator, err }, nil } -func treeFunctionEvaluator(env RideEnvironment, tree *Tree, name string, args proto.Arguments) (*treeEvaluator, error) { +func treeFunctionEvaluator(env RideEnvironment, tree *Tree, name string, args []rideType) (*treeEvaluator, error) { + if name == "" { + name = "default" + } s, err := newEvaluationScope(tree.LibVersion, env) if err != nil { return nil, errors.Wrap(err, "failed to create scope") @@ -477,11 +480,7 @@ func treeFunctionEvaluator(env RideEnvironment, tree *Tree, name string, args pr return nil, errors.Errorf("invalid arguments count %d for function '%s'", l, name) } for i, arg := range args { - a, err := convertArgument(arg) - if err != nil { - return nil, errors.Wrapf(err, "failed to call function '%s'", name) - } - s.pushValue(function.Arguments[i], a) + s.pushValue(function.Arguments[i], arg) } return &treeEvaluator{ dapp: true, diff --git a/pkg/ride/tree_expand_test.go b/pkg/ride/tree_expand_test.go index 6363f06a3e..bb911057ce 100644 --- a/pkg/ride/tree_expand_test.go +++ b/pkg/ride/tree_expand_test.go @@ -22,22 +22,6 @@ func lines(ss ...string) string { return strings.TrimSpace(s.String()) } -func TestTreeExpand(t *testing.T) { - source := `AAIDAAAAAAAAAAgIARIECgIIAgAAAAEBAAAAAmYyAAAAAAkBAAAABXZhbHVlAAAAAQkABBoAAAACBQAAAAR0aGlzAgAAAAF4AAAAAQAAAAFpAQAAAAJmMQAAAAIAAAAJc2Vzc2lvbklkAAAAB3JzYVNpZ24EAAAAAXgJAQAAAAJmMgAAAAAJAQAAAAhXcml0ZVNldAAAAAEFAAAAA25pbAAAAADvU/gM` - src, err := base64.StdEncoding.DecodeString(source) - require.NoError(t, err) - - tree, err := Parse(src) - require.NoError(t, err) - - tree2, _ := Expand(tree) - - require.Equal(t, - `@i\nfunc f1(sessionId,rsaSign) { let x = { value(getInteger(this,"x")) }; WriteSet(nil) }`, - DecompileTree(tree2), - ) -} - func TestTreeExpandWithArguments(t *testing.T) { source := `AAIDAAAAAAAAAAgIARIECgIIAgAAAAIAAAAAAXoAAAAAAAAAAAUBAAAAAmYyAAAAAQAAAAF2CQEAAAAFdmFsdWUAAAABCQAEGgAAAAIFAAAABHRoaXMFAAAAAXYAAAABAAAAAWkBAAAAAmYxAAAAAgAAAAlzZXNzaW9uSWQAAAAHcnNhU2lnbgQAAAABeAkBAAAAAmYyAAAAAQIAAAABZQkBAAAACFdyaXRlU2V0AAAAAQUAAAADbmlsAAAAAN+I8mI=` src, err := base64.StdEncoding.DecodeString(source) @@ -51,7 +35,7 @@ func TestTreeExpandWithArguments(t *testing.T) { require.Equal(t, lines( `let z = { 5 };`, - `@i\nfunc f1(sessionId,rsaSign) { let x = { let v = { "e" }; value(getInteger(this,v)) }; WriteSet(nil) }`, + `@i\nfunc f1(sessionId,rsaSign) { let x = { let v$f2 = { "e" }; value(getInteger(this,v$f2)) }; WriteSet(nil) }`, ), DecompileTree(tree2), ) @@ -119,12 +103,12 @@ func TestTreeExpandWithNamesIntersection(t *testing.T) { tree2, _ := Expand(tree) require.Equal(t, - `@i\nfunc callback() { let x = { let v = { 0 }; 10 }; WriteSet(1100(DataEntry("key",5),nil)) }`, + `@i\nfunc callback() { let x = { let v$call = { 0 }; 10 }; WriteSet(1100(DataEntry("key",5),nil)) }`, DecompileTree(tree2), ) } -func TestTreeExpand11(t *testing.T) { +func TestTreeExpand(t *testing.T) { t.Run("expand with variable and func name collision", func(t *testing.T) { /** {-# STDLIB_VERSION 3 #-} @@ -146,7 +130,7 @@ func TestTreeExpand11(t *testing.T) { tree2, _ := Expand(tree) require.Equal(t, - `(let inc = { 2 }; let v = { inc }; (v + 1) == 3)`, + `(let inc$call = { 2 }; let v$inc = { inc$call }; (v$inc + 1) == 3)`, DecompileTree(tree2), ) rs, err := CallTreeVerifier(nil, tree2) From 0c792d4f8671ea425e871238af52b8ab251609fd Mon Sep 17 00:00:00 2001 From: frozen Date: Fri, 2 Apr 2021 16:21:20 +0300 Subject: [PATCH 54/55] Updated mocks. --- pkg/miner/utxpool/mock.go | 75 +- pkg/mock/grpc.go | 249 ++-- pkg/mock/peer.go | 101 +- pkg/mock/peer_manager.go | 305 ++--- pkg/mock/state.go | 1930 ++++++++++++++-------------- pkg/node/state_fsm/default_mock.go | 47 +- 6 files changed, 1371 insertions(+), 1336 deletions(-) diff --git a/pkg/miner/utxpool/mock.go b/pkg/miner/utxpool/mock.go index d3c9c13cfa..b00dc648da 100644 --- a/pkg/miner/utxpool/mock.go +++ b/pkg/miner/utxpool/mock.go @@ -5,36 +5,37 @@ package utxpool import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" proto "github.com/wavesplatform/gowaves/pkg/proto" state "github.com/wavesplatform/gowaves/pkg/state" - reflect "reflect" ) -// MockstateWrapper is a mock of stateWrapper interface +// MockstateWrapper is a mock of stateWrapper interface. type MockstateWrapper struct { ctrl *gomock.Controller recorder *MockstateWrapperMockRecorder } -// MockstateWrapperMockRecorder is the mock recorder for MockstateWrapper +// MockstateWrapperMockRecorder is the mock recorder for MockstateWrapper. type MockstateWrapperMockRecorder struct { mock *MockstateWrapper } -// NewMockstateWrapper creates a new mock instance +// NewMockstateWrapper creates a new mock instance. func NewMockstateWrapper(ctrl *gomock.Controller) *MockstateWrapper { mock := &MockstateWrapper{ctrl: ctrl} mock.recorder = &MockstateWrapperMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockstateWrapper) EXPECT() *MockstateWrapperMockRecorder { return m.recorder } -// Height mocks base method +// Height mocks base method. func (m *MockstateWrapper) Height() (proto.Height, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Height") @@ -43,65 +44,65 @@ func (m *MockstateWrapper) Height() (proto.Height, error) { return ret0, ret1 } -// Height indicates an expected call of Height +// Height indicates an expected call of Height. func (mr *MockstateWrapperMockRecorder) Height() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockstateWrapper)(nil).Height)) } -// TopBlock mocks base method -func (m *MockstateWrapper) TopBlock() *proto.Block { +// IsActivated mocks base method. +func (m *MockstateWrapper) IsActivated(featureID int16) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TopBlock") - ret0, _ := ret[0].(*proto.Block) - return ret0 + ret := m.ctrl.Call(m, "IsActivated", featureID) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// TopBlock indicates an expected call of TopBlock -func (mr *MockstateWrapperMockRecorder) TopBlock() *gomock.Call { +// IsActivated indicates an expected call of IsActivated. +func (mr *MockstateWrapperMockRecorder) IsActivated(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockstateWrapper)(nil).TopBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockstateWrapper)(nil).IsActivated), featureID) } -// TxValidation mocks base method -func (m *MockstateWrapper) TxValidation(arg0 func(state.TxValidation) error) error { +// Map mocks base method. +func (m *MockstateWrapper) Map(arg0 func(state.NonThreadSafeState) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TxValidation", arg0) + ret := m.ctrl.Call(m, "Map", arg0) ret0, _ := ret[0].(error) return ret0 } -// TxValidation indicates an expected call of TxValidation -func (mr *MockstateWrapperMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { +// Map indicates an expected call of Map. +func (mr *MockstateWrapperMockRecorder) Map(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockstateWrapper)(nil).TxValidation), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockstateWrapper)(nil).Map), arg0) } -// Map mocks base method -func (m *MockstateWrapper) Map(arg0 func(state.NonThreadSafeState) error) error { +// TopBlock mocks base method. +func (m *MockstateWrapper) TopBlock() *proto.Block { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Map", arg0) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "TopBlock") + ret0, _ := ret[0].(*proto.Block) return ret0 } -// Map indicates an expected call of Map -func (mr *MockstateWrapperMockRecorder) Map(arg0 interface{}) *gomock.Call { +// TopBlock indicates an expected call of TopBlock. +func (mr *MockstateWrapperMockRecorder) TopBlock() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockstateWrapper)(nil).Map), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockstateWrapper)(nil).TopBlock)) } -// IsActivated mocks base method -func (m *MockstateWrapper) IsActivated(featureID int16) (bool, error) { +// TxValidation mocks base method. +func (m *MockstateWrapper) TxValidation(arg0 func(state.TxValidation) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActivated", featureID) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "TxValidation", arg0) + ret0, _ := ret[0].(error) + return ret0 } -// IsActivated indicates an expected call of IsActivated -func (mr *MockstateWrapperMockRecorder) IsActivated(featureID interface{}) *gomock.Call { +// TxValidation indicates an expected call of TxValidation. +func (mr *MockstateWrapperMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockstateWrapper)(nil).IsActivated), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockstateWrapper)(nil).TxValidation), arg0) } diff --git a/pkg/mock/grpc.go b/pkg/mock/grpc.go index a6b002add9..a6a0a5bcf3 100644 --- a/pkg/mock/grpc.go +++ b/pkg/mock/grpc.go @@ -6,67 +6,69 @@ package mock import ( context "context" + reflect "reflect" + gomock "github.com/golang/mock/gomock" empty "github.com/golang/protobuf/ptypes/empty" wrappers "github.com/golang/protobuf/ptypes/wrappers" waves "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves" grpc "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves/node/grpc" - reflect "reflect" ) -// MockGrpcHandlers is a mock of GrpcHandlers interface +// MockGrpcHandlers is a mock of GrpcHandlers interface. type MockGrpcHandlers struct { ctrl *gomock.Controller recorder *MockGrpcHandlersMockRecorder } -// MockGrpcHandlersMockRecorder is the mock recorder for MockGrpcHandlers +// MockGrpcHandlersMockRecorder is the mock recorder for MockGrpcHandlers. type MockGrpcHandlersMockRecorder struct { mock *MockGrpcHandlers } -// NewMockGrpcHandlers creates a new mock instance +// NewMockGrpcHandlers creates a new mock instance. func NewMockGrpcHandlers(ctrl *gomock.Controller) *MockGrpcHandlers { mock := &MockGrpcHandlers{ctrl: ctrl} mock.recorder = &MockGrpcHandlersMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockGrpcHandlers) EXPECT() *MockGrpcHandlersMockRecorder { return m.recorder } -// GetBalances mocks base method -func (m *MockGrpcHandlers) GetBalances(arg0 *grpc.BalancesRequest, arg1 grpc.AccountsApi_GetBalancesServer) error { +// Broadcast mocks base method. +func (m *MockGrpcHandlers) Broadcast(arg0 context.Context, arg1 *waves.SignedTransaction) (*waves.SignedTransaction, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBalances", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "Broadcast", arg0, arg1) + ret0, _ := ret[0].(*waves.SignedTransaction) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// GetBalances indicates an expected call of GetBalances -func (mr *MockGrpcHandlersMockRecorder) GetBalances(arg0, arg1 interface{}) *gomock.Call { +// Broadcast indicates an expected call of Broadcast. +func (mr *MockGrpcHandlersMockRecorder) Broadcast(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalances", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBalances), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Broadcast", reflect.TypeOf((*MockGrpcHandlers)(nil).Broadcast), arg0, arg1) } -// GetScript mocks base method -func (m *MockGrpcHandlers) GetScript(arg0 context.Context, arg1 *grpc.AccountRequest) (*grpc.ScriptData, error) { +// GetActivationStatus mocks base method. +func (m *MockGrpcHandlers) GetActivationStatus(arg0 context.Context, arg1 *grpc.ActivationStatusRequest) (*grpc.ActivationStatusResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetScript", arg0, arg1) - ret0, _ := ret[0].(*grpc.ScriptData) + ret := m.ctrl.Call(m, "GetActivationStatus", arg0, arg1) + ret0, _ := ret[0].(*grpc.ActivationStatusResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetScript indicates an expected call of GetScript -func (mr *MockGrpcHandlersMockRecorder) GetScript(arg0, arg1 interface{}) *gomock.Call { +// GetActivationStatus indicates an expected call of GetActivationStatus. +func (mr *MockGrpcHandlersMockRecorder) GetActivationStatus(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScript", reflect.TypeOf((*MockGrpcHandlers)(nil).GetScript), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActivationStatus", reflect.TypeOf((*MockGrpcHandlers)(nil).GetActivationStatus), arg0, arg1) } -// GetActiveLeases mocks base method +// GetActiveLeases mocks base method. func (m *MockGrpcHandlers) GetActiveLeases(arg0 *grpc.AccountRequest, arg1 grpc.AccountsApi_GetActiveLeasesServer) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetActiveLeases", arg0, arg1) @@ -74,174 +76,159 @@ func (m *MockGrpcHandlers) GetActiveLeases(arg0 *grpc.AccountRequest, arg1 grpc. return ret0 } -// GetActiveLeases indicates an expected call of GetActiveLeases +// GetActiveLeases indicates an expected call of GetActiveLeases. func (mr *MockGrpcHandlersMockRecorder) GetActiveLeases(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveLeases", reflect.TypeOf((*MockGrpcHandlers)(nil).GetActiveLeases), arg0, arg1) } -// GetDataEntries mocks base method -func (m *MockGrpcHandlers) GetDataEntries(arg0 *grpc.DataRequest, arg1 grpc.AccountsApi_GetDataEntriesServer) error { +// GetBalances mocks base method. +func (m *MockGrpcHandlers) GetBalances(arg0 *grpc.BalancesRequest, arg1 grpc.AccountsApi_GetBalancesServer) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDataEntries", arg0, arg1) + ret := m.ctrl.Call(m, "GetBalances", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// GetDataEntries indicates an expected call of GetDataEntries -func (mr *MockGrpcHandlersMockRecorder) GetDataEntries(arg0, arg1 interface{}) *gomock.Call { +// GetBalances indicates an expected call of GetBalances. +func (mr *MockGrpcHandlersMockRecorder) GetBalances(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDataEntries", reflect.TypeOf((*MockGrpcHandlers)(nil).GetDataEntries), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalances", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBalances), arg0, arg1) } -// ResolveAlias mocks base method -func (m *MockGrpcHandlers) ResolveAlias(arg0 context.Context, arg1 *wrappers.StringValue) (*wrappers.BytesValue, error) { +// GetBaseTarget mocks base method. +func (m *MockGrpcHandlers) GetBaseTarget(arg0 context.Context, arg1 *empty.Empty) (*grpc.BaseTargetResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveAlias", arg0, arg1) - ret0, _ := ret[0].(*wrappers.BytesValue) + ret := m.ctrl.Call(m, "GetBaseTarget", arg0, arg1) + ret0, _ := ret[0].(*grpc.BaseTargetResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// ResolveAlias indicates an expected call of ResolveAlias -func (mr *MockGrpcHandlersMockRecorder) ResolveAlias(arg0, arg1 interface{}) *gomock.Call { +// GetBaseTarget indicates an expected call of GetBaseTarget. +func (mr *MockGrpcHandlersMockRecorder) GetBaseTarget(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveAlias", reflect.TypeOf((*MockGrpcHandlers)(nil).ResolveAlias), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaseTarget", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBaseTarget), arg0, arg1) } -// GetInfo mocks base method -func (m *MockGrpcHandlers) GetInfo(arg0 context.Context, arg1 *grpc.AssetRequest) (*grpc.AssetInfoResponse, error) { +// GetBlock mocks base method. +func (m *MockGrpcHandlers) GetBlock(arg0 context.Context, arg1 *grpc.BlockRequest) (*grpc.BlockWithHeight, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetInfo", arg0, arg1) - ret0, _ := ret[0].(*grpc.AssetInfoResponse) + ret := m.ctrl.Call(m, "GetBlock", arg0, arg1) + ret0, _ := ret[0].(*grpc.BlockWithHeight) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetInfo indicates an expected call of GetInfo -func (mr *MockGrpcHandlersMockRecorder) GetInfo(arg0, arg1 interface{}) *gomock.Call { +// GetBlock indicates an expected call of GetBlock. +func (mr *MockGrpcHandlersMockRecorder) GetBlock(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInfo", reflect.TypeOf((*MockGrpcHandlers)(nil).GetInfo), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlock", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBlock), arg0, arg1) } -// GetNFTList mocks base method -func (m *MockGrpcHandlers) GetNFTList(arg0 *grpc.NFTRequest, arg1 grpc.AssetsApi_GetNFTListServer) error { +// GetBlockRange mocks base method. +func (m *MockGrpcHandlers) GetBlockRange(arg0 *grpc.BlockRangeRequest, arg1 grpc.BlocksApi_GetBlockRangeServer) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetNFTList", arg0, arg1) + ret := m.ctrl.Call(m, "GetBlockRange", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// GetNFTList indicates an expected call of GetNFTList -func (mr *MockGrpcHandlersMockRecorder) GetNFTList(arg0, arg1 interface{}) *gomock.Call { +// GetBlockRange indicates an expected call of GetBlockRange. +func (mr *MockGrpcHandlersMockRecorder) GetBlockRange(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNFTList", reflect.TypeOf((*MockGrpcHandlers)(nil).GetNFTList), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockRange", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBlockRange), arg0, arg1) } -// GetActivationStatus mocks base method -func (m *MockGrpcHandlers) GetActivationStatus(arg0 context.Context, arg1 *grpc.ActivationStatusRequest) (*grpc.ActivationStatusResponse, error) { +// GetCumulativeScore mocks base method. +func (m *MockGrpcHandlers) GetCumulativeScore(arg0 context.Context, arg1 *empty.Empty) (*grpc.ScoreResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetActivationStatus", arg0, arg1) - ret0, _ := ret[0].(*grpc.ActivationStatusResponse) + ret := m.ctrl.Call(m, "GetCumulativeScore", arg0, arg1) + ret0, _ := ret[0].(*grpc.ScoreResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetActivationStatus indicates an expected call of GetActivationStatus -func (mr *MockGrpcHandlersMockRecorder) GetActivationStatus(arg0, arg1 interface{}) *gomock.Call { +// GetCumulativeScore indicates an expected call of GetCumulativeScore. +func (mr *MockGrpcHandlersMockRecorder) GetCumulativeScore(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActivationStatus", reflect.TypeOf((*MockGrpcHandlers)(nil).GetActivationStatus), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCumulativeScore", reflect.TypeOf((*MockGrpcHandlers)(nil).GetCumulativeScore), arg0, arg1) } -// GetBaseTarget mocks base method -func (m *MockGrpcHandlers) GetBaseTarget(arg0 context.Context, arg1 *empty.Empty) (*grpc.BaseTargetResponse, error) { +// GetCurrentHeight mocks base method. +func (m *MockGrpcHandlers) GetCurrentHeight(arg0 context.Context, arg1 *empty.Empty) (*wrappers.UInt32Value, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBaseTarget", arg0, arg1) - ret0, _ := ret[0].(*grpc.BaseTargetResponse) + ret := m.ctrl.Call(m, "GetCurrentHeight", arg0, arg1) + ret0, _ := ret[0].(*wrappers.UInt32Value) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetBaseTarget indicates an expected call of GetBaseTarget -func (mr *MockGrpcHandlersMockRecorder) GetBaseTarget(arg0, arg1 interface{}) *gomock.Call { +// GetCurrentHeight indicates an expected call of GetCurrentHeight. +func (mr *MockGrpcHandlersMockRecorder) GetCurrentHeight(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaseTarget", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBaseTarget), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentHeight", reflect.TypeOf((*MockGrpcHandlers)(nil).GetCurrentHeight), arg0, arg1) } -// GetCumulativeScore mocks base method -func (m *MockGrpcHandlers) GetCumulativeScore(arg0 context.Context, arg1 *empty.Empty) (*grpc.ScoreResponse, error) { +// GetDataEntries mocks base method. +func (m *MockGrpcHandlers) GetDataEntries(arg0 *grpc.DataRequest, arg1 grpc.AccountsApi_GetDataEntriesServer) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCumulativeScore", arg0, arg1) - ret0, _ := ret[0].(*grpc.ScoreResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "GetDataEntries", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 } -// GetCumulativeScore indicates an expected call of GetCumulativeScore -func (mr *MockGrpcHandlersMockRecorder) GetCumulativeScore(arg0, arg1 interface{}) *gomock.Call { +// GetDataEntries indicates an expected call of GetDataEntries. +func (mr *MockGrpcHandlersMockRecorder) GetDataEntries(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCumulativeScore", reflect.TypeOf((*MockGrpcHandlers)(nil).GetCumulativeScore), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDataEntries", reflect.TypeOf((*MockGrpcHandlers)(nil).GetDataEntries), arg0, arg1) } -// GetBlock mocks base method -func (m *MockGrpcHandlers) GetBlock(arg0 context.Context, arg1 *grpc.BlockRequest) (*grpc.BlockWithHeight, error) { +// GetInfo mocks base method. +func (m *MockGrpcHandlers) GetInfo(arg0 context.Context, arg1 *grpc.AssetRequest) (*grpc.AssetInfoResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBlock", arg0, arg1) - ret0, _ := ret[0].(*grpc.BlockWithHeight) + ret := m.ctrl.Call(m, "GetInfo", arg0, arg1) + ret0, _ := ret[0].(*grpc.AssetInfoResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetBlock indicates an expected call of GetBlock -func (mr *MockGrpcHandlersMockRecorder) GetBlock(arg0, arg1 interface{}) *gomock.Call { +// GetInfo indicates an expected call of GetInfo. +func (mr *MockGrpcHandlersMockRecorder) GetInfo(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlock", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBlock), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInfo", reflect.TypeOf((*MockGrpcHandlers)(nil).GetInfo), arg0, arg1) } -// GetBlockRange mocks base method -func (m *MockGrpcHandlers) GetBlockRange(arg0 *grpc.BlockRangeRequest, arg1 grpc.BlocksApi_GetBlockRangeServer) error { +// GetNFTList mocks base method. +func (m *MockGrpcHandlers) GetNFTList(arg0 *grpc.NFTRequest, arg1 grpc.AssetsApi_GetNFTListServer) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBlockRange", arg0, arg1) + ret := m.ctrl.Call(m, "GetNFTList", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// GetBlockRange indicates an expected call of GetBlockRange -func (mr *MockGrpcHandlersMockRecorder) GetBlockRange(arg0, arg1 interface{}) *gomock.Call { +// GetNFTList indicates an expected call of GetNFTList. +func (mr *MockGrpcHandlersMockRecorder) GetNFTList(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockRange", reflect.TypeOf((*MockGrpcHandlers)(nil).GetBlockRange), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNFTList", reflect.TypeOf((*MockGrpcHandlers)(nil).GetNFTList), arg0, arg1) } -// GetCurrentHeight mocks base method -func (m *MockGrpcHandlers) GetCurrentHeight(arg0 context.Context, arg1 *empty.Empty) (*wrappers.UInt32Value, error) { +// GetScript mocks base method. +func (m *MockGrpcHandlers) GetScript(arg0 context.Context, arg1 *grpc.AccountRequest) (*grpc.ScriptData, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCurrentHeight", arg0, arg1) - ret0, _ := ret[0].(*wrappers.UInt32Value) + ret := m.ctrl.Call(m, "GetScript", arg0, arg1) + ret0, _ := ret[0].(*grpc.ScriptData) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetCurrentHeight indicates an expected call of GetCurrentHeight -func (mr *MockGrpcHandlersMockRecorder) GetCurrentHeight(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentHeight", reflect.TypeOf((*MockGrpcHandlers)(nil).GetCurrentHeight), arg0, arg1) -} - -// GetTransactions mocks base method -func (m *MockGrpcHandlers) GetTransactions(arg0 *grpc.TransactionsRequest, arg1 grpc.TransactionsApi_GetTransactionsServer) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTransactions", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// GetTransactions indicates an expected call of GetTransactions -func (mr *MockGrpcHandlersMockRecorder) GetTransactions(arg0, arg1 interface{}) *gomock.Call { +// GetScript indicates an expected call of GetScript. +func (mr *MockGrpcHandlersMockRecorder) GetScript(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactions", reflect.TypeOf((*MockGrpcHandlers)(nil).GetTransactions), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScript", reflect.TypeOf((*MockGrpcHandlers)(nil).GetScript), arg0, arg1) } -// GetStateChanges mocks base method +// GetStateChanges mocks base method. func (m *MockGrpcHandlers) GetStateChanges(arg0 *grpc.TransactionsRequest, arg1 grpc.TransactionsApi_GetStateChangesServer) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetStateChanges", arg0, arg1) @@ -249,13 +236,13 @@ func (m *MockGrpcHandlers) GetStateChanges(arg0 *grpc.TransactionsRequest, arg1 return ret0 } -// GetStateChanges indicates an expected call of GetStateChanges +// GetStateChanges indicates an expected call of GetStateChanges. func (mr *MockGrpcHandlersMockRecorder) GetStateChanges(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStateChanges", reflect.TypeOf((*MockGrpcHandlers)(nil).GetStateChanges), arg0, arg1) } -// GetStatuses mocks base method +// GetStatuses mocks base method. func (m *MockGrpcHandlers) GetStatuses(arg0 *grpc.TransactionsByIdRequest, arg1 grpc.TransactionsApi_GetStatusesServer) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetStatuses", arg0, arg1) @@ -263,13 +250,27 @@ func (m *MockGrpcHandlers) GetStatuses(arg0 *grpc.TransactionsByIdRequest, arg1 return ret0 } -// GetStatuses indicates an expected call of GetStatuses +// GetStatuses indicates an expected call of GetStatuses. func (mr *MockGrpcHandlersMockRecorder) GetStatuses(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStatuses", reflect.TypeOf((*MockGrpcHandlers)(nil).GetStatuses), arg0, arg1) } -// GetUnconfirmed mocks base method +// GetTransactions mocks base method. +func (m *MockGrpcHandlers) GetTransactions(arg0 *grpc.TransactionsRequest, arg1 grpc.TransactionsApi_GetTransactionsServer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTransactions", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// GetTransactions indicates an expected call of GetTransactions. +func (mr *MockGrpcHandlersMockRecorder) GetTransactions(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactions", reflect.TypeOf((*MockGrpcHandlers)(nil).GetTransactions), arg0, arg1) +} + +// GetUnconfirmed mocks base method. func (m *MockGrpcHandlers) GetUnconfirmed(arg0 *grpc.TransactionsRequest, arg1 grpc.TransactionsApi_GetUnconfirmedServer) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnconfirmed", arg0, arg1) @@ -277,38 +278,38 @@ func (m *MockGrpcHandlers) GetUnconfirmed(arg0 *grpc.TransactionsRequest, arg1 g return ret0 } -// GetUnconfirmed indicates an expected call of GetUnconfirmed +// GetUnconfirmed indicates an expected call of GetUnconfirmed. func (mr *MockGrpcHandlersMockRecorder) GetUnconfirmed(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnconfirmed", reflect.TypeOf((*MockGrpcHandlers)(nil).GetUnconfirmed), arg0, arg1) } -// Sign mocks base method -func (m *MockGrpcHandlers) Sign(arg0 context.Context, arg1 *grpc.SignRequest) (*waves.SignedTransaction, error) { +// ResolveAlias mocks base method. +func (m *MockGrpcHandlers) ResolveAlias(arg0 context.Context, arg1 *wrappers.StringValue) (*wrappers.BytesValue, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Sign", arg0, arg1) - ret0, _ := ret[0].(*waves.SignedTransaction) + ret := m.ctrl.Call(m, "ResolveAlias", arg0, arg1) + ret0, _ := ret[0].(*wrappers.BytesValue) ret1, _ := ret[1].(error) return ret0, ret1 } -// Sign indicates an expected call of Sign -func (mr *MockGrpcHandlersMockRecorder) Sign(arg0, arg1 interface{}) *gomock.Call { +// ResolveAlias indicates an expected call of ResolveAlias. +func (mr *MockGrpcHandlersMockRecorder) ResolveAlias(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sign", reflect.TypeOf((*MockGrpcHandlers)(nil).Sign), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveAlias", reflect.TypeOf((*MockGrpcHandlers)(nil).ResolveAlias), arg0, arg1) } -// Broadcast mocks base method -func (m *MockGrpcHandlers) Broadcast(arg0 context.Context, arg1 *waves.SignedTransaction) (*waves.SignedTransaction, error) { +// Sign mocks base method. +func (m *MockGrpcHandlers) Sign(arg0 context.Context, arg1 *grpc.SignRequest) (*waves.SignedTransaction, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Broadcast", arg0, arg1) + ret := m.ctrl.Call(m, "Sign", arg0, arg1) ret0, _ := ret[0].(*waves.SignedTransaction) ret1, _ := ret[1].(error) return ret0, ret1 } -// Broadcast indicates an expected call of Broadcast -func (mr *MockGrpcHandlersMockRecorder) Broadcast(arg0, arg1 interface{}) *gomock.Call { +// Sign indicates an expected call of Sign. +func (mr *MockGrpcHandlersMockRecorder) Sign(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Broadcast", reflect.TypeOf((*MockGrpcHandlers)(nil).Broadcast), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sign", reflect.TypeOf((*MockGrpcHandlers)(nil).Sign), arg0, arg1) } diff --git a/pkg/mock/peer.go b/pkg/mock/peer.go index 895e33d201..e6f5f412bf 100644 --- a/pkg/mock/peer.go +++ b/pkg/mock/peer.go @@ -5,51 +5,38 @@ package mock import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" conn "github.com/wavesplatform/gowaves/pkg/p2p/conn" peer "github.com/wavesplatform/gowaves/pkg/p2p/peer" proto "github.com/wavesplatform/gowaves/pkg/proto" - reflect "reflect" ) -// MockPeer is a mock of Peer interface +// MockPeer is a mock of Peer interface. type MockPeer struct { ctrl *gomock.Controller recorder *MockPeerMockRecorder } -// MockPeerMockRecorder is the mock recorder for MockPeer +// MockPeerMockRecorder is the mock recorder for MockPeer. type MockPeerMockRecorder struct { mock *MockPeer } -// NewMockPeer creates a new mock instance +// NewMockPeer creates a new mock instance. func NewMockPeer(ctrl *gomock.Controller) *MockPeer { mock := &MockPeer{ctrl: ctrl} mock.recorder = &MockPeerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockPeer) EXPECT() *MockPeerMockRecorder { return m.recorder } -// Direction mocks base method -func (m *MockPeer) Direction() peer.Direction { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Direction") - ret0, _ := ret[0].(peer.Direction) - return ret0 -} - -// Direction indicates an expected call of Direction -func (mr *MockPeerMockRecorder) Direction() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Direction", reflect.TypeOf((*MockPeer)(nil).Direction)) -} - -// Close mocks base method +// Close mocks base method. func (m *MockPeer) Close() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Close") @@ -57,67 +44,69 @@ func (m *MockPeer) Close() error { return ret0 } -// Close indicates an expected call of Close +// Close indicates an expected call of Close. func (mr *MockPeerMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeer)(nil).Close)) } -// SendMessage mocks base method -func (m *MockPeer) SendMessage(arg0 proto.Message) { +// Connection mocks base method. +func (m *MockPeer) Connection() conn.Connection { m.ctrl.T.Helper() - m.ctrl.Call(m, "SendMessage", arg0) + ret := m.ctrl.Call(m, "Connection") + ret0, _ := ret[0].(conn.Connection) + return ret0 } -// SendMessage indicates an expected call of SendMessage -func (mr *MockPeerMockRecorder) SendMessage(arg0 interface{}) *gomock.Call { +// Connection indicates an expected call of Connection. +func (mr *MockPeerMockRecorder) Connection() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMessage", reflect.TypeOf((*MockPeer)(nil).SendMessage), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connection", reflect.TypeOf((*MockPeer)(nil).Connection)) } -// ID mocks base method -func (m *MockPeer) ID() string { +// Direction mocks base method. +func (m *MockPeer) Direction() peer.Direction { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ID") - ret0, _ := ret[0].(string) + ret := m.ctrl.Call(m, "Direction") + ret0, _ := ret[0].(peer.Direction) return ret0 } -// ID indicates an expected call of ID -func (mr *MockPeerMockRecorder) ID() *gomock.Call { +// Direction indicates an expected call of Direction. +func (mr *MockPeerMockRecorder) Direction() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockPeer)(nil).ID)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Direction", reflect.TypeOf((*MockPeer)(nil).Direction)) } -// Connection mocks base method -func (m *MockPeer) Connection() conn.Connection { +// Handshake mocks base method. +func (m *MockPeer) Handshake() proto.Handshake { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Connection") - ret0, _ := ret[0].(conn.Connection) + ret := m.ctrl.Call(m, "Handshake") + ret0, _ := ret[0].(proto.Handshake) return ret0 } -// Connection indicates an expected call of Connection -func (mr *MockPeerMockRecorder) Connection() *gomock.Call { +// Handshake indicates an expected call of Handshake. +func (mr *MockPeerMockRecorder) Handshake() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connection", reflect.TypeOf((*MockPeer)(nil).Connection)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handshake", reflect.TypeOf((*MockPeer)(nil).Handshake)) } -// Handshake mocks base method -func (m *MockPeer) Handshake() proto.Handshake { +// ID mocks base method. +func (m *MockPeer) ID() string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Handshake") - ret0, _ := ret[0].(proto.Handshake) + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) return ret0 } -// Handshake indicates an expected call of Handshake -func (mr *MockPeerMockRecorder) Handshake() *gomock.Call { +// ID indicates an expected call of ID. +func (mr *MockPeerMockRecorder) ID() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handshake", reflect.TypeOf((*MockPeer)(nil).Handshake)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockPeer)(nil).ID)) } -// RemoteAddr mocks base method +// RemoteAddr mocks base method. func (m *MockPeer) RemoteAddr() proto.TCPAddr { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RemoteAddr") @@ -125,8 +114,20 @@ func (m *MockPeer) RemoteAddr() proto.TCPAddr { return ret0 } -// RemoteAddr indicates an expected call of RemoteAddr +// RemoteAddr indicates an expected call of RemoteAddr. func (mr *MockPeerMockRecorder) RemoteAddr() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoteAddr", reflect.TypeOf((*MockPeer)(nil).RemoteAddr)) } + +// SendMessage mocks base method. +func (m *MockPeer) SendMessage(arg0 proto.Message) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SendMessage", arg0) +} + +// SendMessage indicates an expected call of SendMessage. +func (mr *MockPeerMockRecorder) SendMessage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMessage", reflect.TypeOf((*MockPeer)(nil).SendMessage), arg0) +} diff --git a/pkg/mock/peer_manager.go b/pkg/mock/peer_manager.go index 60a0697437..cda43493f1 100644 --- a/pkg/mock/peer_manager.go +++ b/pkg/mock/peer_manager.go @@ -6,67 +6,104 @@ package mock import ( context "context" - gomock "github.com/golang/mock/gomock" - peer "github.com/wavesplatform/gowaves/pkg/p2p/peer" - proto "github.com/wavesplatform/gowaves/pkg/proto" big "math/big" net "net" reflect "reflect" + + gomock "github.com/golang/mock/gomock" + peer "github.com/wavesplatform/gowaves/pkg/p2p/peer" + proto "github.com/wavesplatform/gowaves/pkg/proto" ) -// MockPeerManager is a mock of PeerManager interface +// MockPeerManager is a mock of PeerManager interface. type MockPeerManager struct { ctrl *gomock.Controller recorder *MockPeerManagerMockRecorder } -// MockPeerManagerMockRecorder is the mock recorder for MockPeerManager +// MockPeerManagerMockRecorder is the mock recorder for MockPeerManager. type MockPeerManagerMockRecorder struct { mock *MockPeerManager } -// NewMockPeerManager creates a new mock instance +// NewMockPeerManager creates a new mock instance. func NewMockPeerManager(ctrl *gomock.Controller) *MockPeerManager { mock := &MockPeerManager{ctrl: ctrl} mock.recorder = &MockPeerManagerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockPeerManager) EXPECT() *MockPeerManagerMockRecorder { return m.recorder } -// Connected mocks base method -func (m *MockPeerManager) Connected(arg0 peer.Peer) (peer.Peer, bool) { +// AddConnected mocks base method. +func (m *MockPeerManager) AddConnected(arg0 peer.Peer) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Connected", arg0) - ret0, _ := ret[0].(peer.Peer) - ret1, _ := ret[1].(bool) - return ret0, ret1 + m.ctrl.Call(m, "AddConnected", arg0) } -// Connected indicates an expected call of Connected -func (mr *MockPeerManagerMockRecorder) Connected(arg0 interface{}) *gomock.Call { +// AddConnected indicates an expected call of AddConnected. +func (mr *MockPeerManagerMockRecorder) AddConnected(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connected", reflect.TypeOf((*MockPeerManager)(nil).Connected), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddConnected", reflect.TypeOf((*MockPeerManager)(nil).AddConnected), arg0) } -// NewConnection mocks base method -func (m *MockPeerManager) NewConnection(arg0 peer.Peer) error { +// AskPeers mocks base method. +func (m *MockPeerManager) AskPeers() { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewConnection", arg0) + m.ctrl.Call(m, "AskPeers") +} + +// AskPeers indicates an expected call of AskPeers. +func (mr *MockPeerManagerMockRecorder) AskPeers() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AskPeers", reflect.TypeOf((*MockPeerManager)(nil).AskPeers)) +} + +// Close mocks base method. +func (m *MockPeerManager) Close() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Close") +} + +// Close indicates an expected call of Close. +func (mr *MockPeerManagerMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeerManager)(nil).Close)) +} + +// Connect mocks base method. +func (m *MockPeerManager) Connect(arg0 context.Context, arg1 proto.TCPAddr) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Connect", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// NewConnection indicates an expected call of NewConnection -func (mr *MockPeerManagerMockRecorder) NewConnection(arg0 interface{}) *gomock.Call { +// Connect indicates an expected call of Connect. +func (mr *MockPeerManagerMockRecorder) Connect(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewConnection", reflect.TypeOf((*MockPeerManager)(nil).NewConnection), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockPeerManager)(nil).Connect), arg0, arg1) +} + +// Connected mocks base method. +func (m *MockPeerManager) Connected(arg0 peer.Peer) (peer.Peer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Connected", arg0) + ret0, _ := ret[0].(peer.Peer) + ret1, _ := ret[1].(bool) + return ret0, ret1 } -// ConnectedCount mocks base method +// Connected indicates an expected call of Connected. +func (mr *MockPeerManagerMockRecorder) Connected(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connected", reflect.TypeOf((*MockPeerManager)(nil).Connected), arg0) +} + +// ConnectedCount mocks base method. func (m *MockPeerManager) ConnectedCount() int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ConnectedCount") @@ -74,40 +111,52 @@ func (m *MockPeerManager) ConnectedCount() int { return ret0 } -// ConnectedCount indicates an expected call of ConnectedCount +// ConnectedCount indicates an expected call of ConnectedCount. func (mr *MockPeerManagerMockRecorder) ConnectedCount() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConnectedCount", reflect.TypeOf((*MockPeerManager)(nil).ConnectedCount)) } -// InOutCount mocks base method -func (m *MockPeerManager) InOutCount() (int, int) { +// Disconnect mocks base method. +func (m *MockPeerManager) Disconnect(arg0 peer.Peer) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InOutCount") - ret0, _ := ret[0].(int) - ret1, _ := ret[1].(int) - return ret0, ret1 + m.ctrl.Call(m, "Disconnect", arg0) } -// InOutCount indicates an expected call of InOutCount -func (mr *MockPeerManagerMockRecorder) InOutCount() *gomock.Call { +// Disconnect indicates an expected call of Disconnect. +func (mr *MockPeerManagerMockRecorder) Disconnect(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InOutCount", reflect.TypeOf((*MockPeerManager)(nil).InOutCount)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Disconnect", reflect.TypeOf((*MockPeerManager)(nil).Disconnect), arg0) } -// EachConnected mocks base method +// EachConnected mocks base method. func (m *MockPeerManager) EachConnected(arg0 func(peer.Peer, *proto.Score)) { m.ctrl.T.Helper() m.ctrl.Call(m, "EachConnected", arg0) } -// EachConnected indicates an expected call of EachConnected +// EachConnected indicates an expected call of EachConnected. func (mr *MockPeerManagerMockRecorder) EachConnected(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EachConnected", reflect.TypeOf((*MockPeerManager)(nil).EachConnected), arg0) } -// IsSuspended mocks base method +// InOutCount mocks base method. +func (m *MockPeerManager) InOutCount() (int, int) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InOutCount") + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(int) + return ret0, ret1 +} + +// InOutCount indicates an expected call of InOutCount. +func (mr *MockPeerManagerMockRecorder) InOutCount() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InOutCount", reflect.TypeOf((*MockPeerManager)(nil).InOutCount)) +} + +// IsSuspended mocks base method. func (m *MockPeerManager) IsSuspended(arg0 peer.Peer) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsSuspended", arg0) @@ -115,51 +164,42 @@ func (m *MockPeerManager) IsSuspended(arg0 peer.Peer) bool { return ret0 } -// IsSuspended indicates an expected call of IsSuspended +// IsSuspended indicates an expected call of IsSuspended. func (mr *MockPeerManagerMockRecorder) IsSuspended(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSuspended", reflect.TypeOf((*MockPeerManager)(nil).IsSuspended), arg0) } -// Suspend mocks base method -func (m *MockPeerManager) Suspend(arg0 peer.Peer, arg1 string) { +// KnownPeers mocks base method. +func (m *MockPeerManager) KnownPeers() ([]proto.TCPAddr, error) { m.ctrl.T.Helper() - m.ctrl.Call(m, "Suspend", arg0, arg1) + ret := m.ctrl.Call(m, "KnownPeers") + ret0, _ := ret[0].([]proto.TCPAddr) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// Suspend indicates an expected call of Suspend -func (mr *MockPeerManagerMockRecorder) Suspend(arg0, arg1 interface{}) *gomock.Call { +// KnownPeers indicates an expected call of KnownPeers. +func (mr *MockPeerManagerMockRecorder) KnownPeers() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspend", reflect.TypeOf((*MockPeerManager)(nil).Suspend), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KnownPeers", reflect.TypeOf((*MockPeerManager)(nil).KnownPeers)) } -// Suspended mocks base method -func (m *MockPeerManager) Suspended() []string { +// NewConnection mocks base method. +func (m *MockPeerManager) NewConnection(arg0 peer.Peer) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Suspended") - ret0, _ := ret[0].([]string) + ret := m.ctrl.Call(m, "NewConnection", arg0) + ret0, _ := ret[0].(error) return ret0 } -// Suspended indicates an expected call of Suspended -func (mr *MockPeerManagerMockRecorder) Suspended() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspended", reflect.TypeOf((*MockPeerManager)(nil).Suspended)) -} - -// AddConnected mocks base method -func (m *MockPeerManager) AddConnected(arg0 peer.Peer) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "AddConnected", arg0) -} - -// AddConnected indicates an expected call of AddConnected -func (mr *MockPeerManagerMockRecorder) AddConnected(arg0 interface{}) *gomock.Call { +// NewConnection indicates an expected call of NewConnection. +func (mr *MockPeerManagerMockRecorder) NewConnection(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddConnected", reflect.TypeOf((*MockPeerManager)(nil).AddConnected), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewConnection", reflect.TypeOf((*MockPeerManager)(nil).NewConnection), arg0) } -// PeerWithHighestScore mocks base method +// PeerWithHighestScore mocks base method. func (m *MockPeerManager) PeerWithHighestScore() (peer.Peer, *big.Int, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PeerWithHighestScore") @@ -169,94 +209,54 @@ func (m *MockPeerManager) PeerWithHighestScore() (peer.Peer, *big.Int, bool) { return ret0, ret1, ret2 } -// PeerWithHighestScore indicates an expected call of PeerWithHighestScore +// PeerWithHighestScore indicates an expected call of PeerWithHighestScore. func (mr *MockPeerManagerMockRecorder) PeerWithHighestScore() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerWithHighestScore", reflect.TypeOf((*MockPeerManager)(nil).PeerWithHighestScore)) } -// UpdateScore mocks base method -func (m *MockPeerManager) UpdateScore(p peer.Peer, score *proto.Score) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateScore", p, score) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateScore indicates an expected call of UpdateScore -func (mr *MockPeerManagerMockRecorder) UpdateScore(p, score interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateScore", reflect.TypeOf((*MockPeerManager)(nil).UpdateScore), p, score) -} - -// UpdateKnownPeers mocks base method -func (m *MockPeerManager) UpdateKnownPeers(arg0 []proto.TCPAddr) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateKnownPeers", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateKnownPeers indicates an expected call of UpdateKnownPeers -func (mr *MockPeerManagerMockRecorder) UpdateKnownPeers(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateKnownPeers", reflect.TypeOf((*MockPeerManager)(nil).UpdateKnownPeers), arg0) -} - -// KnownPeers mocks base method -func (m *MockPeerManager) KnownPeers() ([]proto.TCPAddr, error) { +// Score mocks base method. +func (m *MockPeerManager) Score(p peer.Peer) (*proto.Score, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "KnownPeers") - ret0, _ := ret[0].([]proto.TCPAddr) + ret := m.ctrl.Call(m, "Score", p) + ret0, _ := ret[0].(*proto.Score) ret1, _ := ret[1].(error) return ret0, ret1 } -// KnownPeers indicates an expected call of KnownPeers -func (mr *MockPeerManagerMockRecorder) KnownPeers() *gomock.Call { +// Score indicates an expected call of Score. +func (mr *MockPeerManagerMockRecorder) Score(p interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KnownPeers", reflect.TypeOf((*MockPeerManager)(nil).KnownPeers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Score", reflect.TypeOf((*MockPeerManager)(nil).Score), p) } -// Close mocks base method -func (m *MockPeerManager) Close() { +// SpawnIncomingConnection mocks base method. +func (m *MockPeerManager) SpawnIncomingConnection(ctx context.Context, conn net.Conn) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "Close") + ret := m.ctrl.Call(m, "SpawnIncomingConnection", ctx, conn) + ret0, _ := ret[0].(error) + return ret0 } -// Close indicates an expected call of Close -func (mr *MockPeerManagerMockRecorder) Close() *gomock.Call { +// SpawnIncomingConnection indicates an expected call of SpawnIncomingConnection. +func (mr *MockPeerManagerMockRecorder) SpawnIncomingConnection(ctx, conn interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeerManager)(nil).Close)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnIncomingConnection", reflect.TypeOf((*MockPeerManager)(nil).SpawnIncomingConnection), ctx, conn) } -// SpawnOutgoingConnections mocks base method +// SpawnOutgoingConnections mocks base method. func (m *MockPeerManager) SpawnOutgoingConnections(arg0 context.Context) { m.ctrl.T.Helper() m.ctrl.Call(m, "SpawnOutgoingConnections", arg0) } -// SpawnOutgoingConnections indicates an expected call of SpawnOutgoingConnections +// SpawnOutgoingConnections indicates an expected call of SpawnOutgoingConnections. func (mr *MockPeerManagerMockRecorder) SpawnOutgoingConnections(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnOutgoingConnections", reflect.TypeOf((*MockPeerManager)(nil).SpawnOutgoingConnections), arg0) } -// SpawnIncomingConnection mocks base method -func (m *MockPeerManager) SpawnIncomingConnection(ctx context.Context, conn net.Conn) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpawnIncomingConnection", ctx, conn) - ret0, _ := ret[0].(error) - return ret0 -} - -// SpawnIncomingConnection indicates an expected call of SpawnIncomingConnection -func (mr *MockPeerManagerMockRecorder) SpawnIncomingConnection(ctx, conn interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnIncomingConnection", reflect.TypeOf((*MockPeerManager)(nil).SpawnIncomingConnection), ctx, conn) -} - -// Spawned mocks base method +// Spawned mocks base method. func (m *MockPeerManager) Spawned() []proto.IpPort { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Spawned") @@ -264,61 +264,62 @@ func (m *MockPeerManager) Spawned() []proto.IpPort { return ret0 } -// Spawned indicates an expected call of Spawned +// Spawned indicates an expected call of Spawned. func (mr *MockPeerManagerMockRecorder) Spawned() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Spawned", reflect.TypeOf((*MockPeerManager)(nil).Spawned)) } -// Connect mocks base method -func (m *MockPeerManager) Connect(arg0 context.Context, arg1 proto.TCPAddr) error { +// Suspend mocks base method. +func (m *MockPeerManager) Suspend(arg0 peer.Peer, arg1 string) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Connect", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 + m.ctrl.Call(m, "Suspend", arg0, arg1) } -// Connect indicates an expected call of Connect -func (mr *MockPeerManagerMockRecorder) Connect(arg0, arg1 interface{}) *gomock.Call { +// Suspend indicates an expected call of Suspend. +func (mr *MockPeerManagerMockRecorder) Suspend(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockPeerManager)(nil).Connect), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspend", reflect.TypeOf((*MockPeerManager)(nil).Suspend), arg0, arg1) } -// Score mocks base method -func (m *MockPeerManager) Score(p peer.Peer) (*proto.Score, error) { +// Suspended mocks base method. +func (m *MockPeerManager) Suspended() []string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Score", p) - ret0, _ := ret[0].(*proto.Score) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "Suspended") + ret0, _ := ret[0].([]string) + return ret0 } -// Score indicates an expected call of Score -func (mr *MockPeerManagerMockRecorder) Score(p interface{}) *gomock.Call { +// Suspended indicates an expected call of Suspended. +func (mr *MockPeerManagerMockRecorder) Suspended() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Score", reflect.TypeOf((*MockPeerManager)(nil).Score), p) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Suspended", reflect.TypeOf((*MockPeerManager)(nil).Suspended)) } -// AskPeers mocks base method -func (m *MockPeerManager) AskPeers() { +// UpdateKnownPeers mocks base method. +func (m *MockPeerManager) UpdateKnownPeers(arg0 []proto.TCPAddr) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "AskPeers") + ret := m.ctrl.Call(m, "UpdateKnownPeers", arg0) + ret0, _ := ret[0].(error) + return ret0 } -// AskPeers indicates an expected call of AskPeers -func (mr *MockPeerManagerMockRecorder) AskPeers() *gomock.Call { +// UpdateKnownPeers indicates an expected call of UpdateKnownPeers. +func (mr *MockPeerManagerMockRecorder) UpdateKnownPeers(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AskPeers", reflect.TypeOf((*MockPeerManager)(nil).AskPeers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateKnownPeers", reflect.TypeOf((*MockPeerManager)(nil).UpdateKnownPeers), arg0) } -// Disconnect mocks base method -func (m *MockPeerManager) Disconnect(arg0 peer.Peer) { +// UpdateScore mocks base method. +func (m *MockPeerManager) UpdateScore(p peer.Peer, score *proto.Score) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "Disconnect", arg0) + ret := m.ctrl.Call(m, "UpdateScore", p, score) + ret0, _ := ret[0].(error) + return ret0 } -// Disconnect indicates an expected call of Disconnect -func (mr *MockPeerManagerMockRecorder) Disconnect(arg0 interface{}) *gomock.Call { +// UpdateScore indicates an expected call of UpdateScore. +func (mr *MockPeerManagerMockRecorder) UpdateScore(p, score interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Disconnect", reflect.TypeOf((*MockPeerManager)(nil).Disconnect), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateScore", reflect.TypeOf((*MockPeerManager)(nil).UpdateScore), p, score) } diff --git a/pkg/mock/state.go b/pkg/mock/state.go index d377cedcf4..d6c109e0f0 100644 --- a/pkg/mock/state.go +++ b/pkg/mock/state.go @@ -5,55 +5,55 @@ package mock import ( + big "math/big" + reflect "reflect" + gomock "github.com/golang/mock/gomock" crypto "github.com/wavesplatform/gowaves/pkg/crypto" proto "github.com/wavesplatform/gowaves/pkg/proto" settings "github.com/wavesplatform/gowaves/pkg/settings" state "github.com/wavesplatform/gowaves/pkg/state" - big "math/big" - reflect "reflect" + types "github.com/wavesplatform/gowaves/pkg/types" ) -// MockTransactionIterator is a mock of TransactionIterator interface +// MockTransactionIterator is a mock of TransactionIterator interface. type MockTransactionIterator struct { ctrl *gomock.Controller recorder *MockTransactionIteratorMockRecorder } -// MockTransactionIteratorMockRecorder is the mock recorder for MockTransactionIterator +// MockTransactionIteratorMockRecorder is the mock recorder for MockTransactionIterator. type MockTransactionIteratorMockRecorder struct { mock *MockTransactionIterator } -// NewMockTransactionIterator creates a new mock instance +// NewMockTransactionIterator creates a new mock instance. func NewMockTransactionIterator(ctrl *gomock.Controller) *MockTransactionIterator { mock := &MockTransactionIterator{ctrl: ctrl} mock.recorder = &MockTransactionIteratorMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockTransactionIterator) EXPECT() *MockTransactionIteratorMockRecorder { return m.recorder } -// Transaction mocks base method -func (m *MockTransactionIterator) Transaction() (proto.Transaction, bool, error) { +// Error mocks base method. +func (m *MockTransactionIterator) Error() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Transaction") - ret0, _ := ret[0].(proto.Transaction) - ret1, _ := ret[1].(bool) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret := m.ctrl.Call(m, "Error") + ret0, _ := ret[0].(error) + return ret0 } -// Transaction indicates an expected call of Transaction -func (mr *MockTransactionIteratorMockRecorder) Transaction() *gomock.Call { +// Error indicates an expected call of Error. +func (mr *MockTransactionIteratorMockRecorder) Error() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transaction", reflect.TypeOf((*MockTransactionIterator)(nil).Transaction)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockTransactionIterator)(nil).Error)) } -// Next mocks base method +// Next mocks base method. func (m *MockTransactionIterator) Next() bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Next") @@ -61,151 +61,199 @@ func (m *MockTransactionIterator) Next() bool { return ret0 } -// Next indicates an expected call of Next +// Next indicates an expected call of Next. func (mr *MockTransactionIteratorMockRecorder) Next() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Next", reflect.TypeOf((*MockTransactionIterator)(nil).Next)) } -// Release mocks base method +// Release mocks base method. func (m *MockTransactionIterator) Release() { m.ctrl.T.Helper() m.ctrl.Call(m, "Release") } -// Release indicates an expected call of Release +// Release indicates an expected call of Release. func (mr *MockTransactionIteratorMockRecorder) Release() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Release", reflect.TypeOf((*MockTransactionIterator)(nil).Release)) } -// Error mocks base method -func (m *MockTransactionIterator) Error() error { +// Transaction mocks base method. +func (m *MockTransactionIterator) Transaction() (proto.Transaction, bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Error") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "Transaction") + ret0, _ := ret[0].(proto.Transaction) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } -// Error indicates an expected call of Error -func (mr *MockTransactionIteratorMockRecorder) Error() *gomock.Call { +// Transaction indicates an expected call of Transaction. +func (mr *MockTransactionIteratorMockRecorder) Transaction() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockTransactionIterator)(nil).Error)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transaction", reflect.TypeOf((*MockTransactionIterator)(nil).Transaction)) } -// MockStateInfo is a mock of StateInfo interface +// MockStateInfo is a mock of StateInfo interface. type MockStateInfo struct { ctrl *gomock.Controller recorder *MockStateInfoMockRecorder } -// MockStateInfoMockRecorder is the mock recorder for MockStateInfo +// MockStateInfoMockRecorder is the mock recorder for MockStateInfo. type MockStateInfoMockRecorder struct { mock *MockStateInfo } -// NewMockStateInfo creates a new mock instance +// NewMockStateInfo creates a new mock instance. func NewMockStateInfo(ctrl *gomock.Controller) *MockStateInfo { mock := &MockStateInfo{ctrl: ctrl} mock.recorder = &MockStateInfoMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockStateInfo) EXPECT() *MockStateInfoMockRecorder { return m.recorder } -// TopBlock mocks base method -func (m *MockStateInfo) TopBlock() *proto.Block { +// AccountBalance mocks base method. +func (m *MockStateInfo) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TopBlock") - ret0, _ := ret[0].(*proto.Block) - return ret0 + ret := m.ctrl.Call(m, "AccountBalance", account, asset) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// TopBlock indicates an expected call of TopBlock -func (mr *MockStateInfoMockRecorder) TopBlock() *gomock.Call { +// AccountBalance indicates an expected call of AccountBalance. +func (mr *MockStateInfoMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockStateInfo)(nil).TopBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockStateInfo)(nil).AccountBalance), account, asset) } -// Block mocks base method -func (m *MockStateInfo) Block(blockID proto.BlockID) (*proto.Block, error) { +// ActivationHeight mocks base method. +func (m *MockStateInfo) ActivationHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Block", blockID) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ActivationHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// Block indicates an expected call of Block -func (mr *MockStateInfoMockRecorder) Block(blockID interface{}) *gomock.Call { +// ActivationHeight indicates an expected call of ActivationHeight. +func (mr *MockStateInfoMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockStateInfo)(nil).Block), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockStateInfo)(nil).ActivationHeight), featureID) } -// BlockByHeight mocks base method -func (m *MockStateInfo) BlockByHeight(height proto.Height) (*proto.Block, error) { +// AddrByAlias mocks base method. +func (m *MockStateInfo) AddrByAlias(alias proto.Alias) (proto.Address, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByHeight", height) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "AddrByAlias", alias) + ret0, _ := ret[0].(proto.Address) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockByHeight indicates an expected call of BlockByHeight -func (mr *MockStateInfoMockRecorder) BlockByHeight(height interface{}) *gomock.Call { +// AddrByAlias indicates an expected call of AddrByAlias. +func (mr *MockStateInfoMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockStateInfo)(nil).BlockByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockStateInfo)(nil).AddrByAlias), alias) } -// Header mocks base method -func (m *MockStateInfo) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { +// AllFeatures mocks base method. +func (m *MockStateInfo) AllFeatures() ([]int16, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Header", blockID) - ret0, _ := ret[0].(*proto.BlockHeader) + ret := m.ctrl.Call(m, "AllFeatures") + ret0, _ := ret[0].([]int16) ret1, _ := ret[1].(error) return ret0, ret1 } -// Header indicates an expected call of Header -func (mr *MockStateInfoMockRecorder) Header(blockID interface{}) *gomock.Call { +// AllFeatures indicates an expected call of AllFeatures. +func (mr *MockStateInfoMockRecorder) AllFeatures() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockStateInfo)(nil).Header), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockStateInfo)(nil).AllFeatures)) } -// HeaderByHeight mocks base method -func (m *MockStateInfo) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { +// ApprovalHeight mocks base method. +func (m *MockStateInfo) ApprovalHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByHeight", height) - ret0, _ := ret[0].(*proto.BlockHeader) + ret := m.ctrl.Call(m, "ApprovalHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// HeaderByHeight indicates an expected call of HeaderByHeight -func (mr *MockStateInfoMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { +// ApprovalHeight indicates an expected call of ApprovalHeight. +func (mr *MockStateInfoMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockStateInfo)(nil).HeaderByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockStateInfo)(nil).ApprovalHeight), featureID) } -// Height mocks base method -func (m *MockStateInfo) Height() (proto.Height, error) { +// AssetInfo mocks base method. +func (m *MockStateInfo) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Height") - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "AssetInfo", assetID) + ret0, _ := ret[0].(*proto.AssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// Height indicates an expected call of Height -func (mr *MockStateInfoMockRecorder) Height() *gomock.Call { +// AssetInfo indicates an expected call of AssetInfo. +func (mr *MockStateInfoMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockStateInfo)(nil).Height)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockStateInfo)(nil).AssetInfo), assetID) +} + +// AssetIsSponsored mocks base method. +func (m *MockStateInfo) AssetIsSponsored(assetID crypto.Digest) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssetIsSponsored indicates an expected call of AssetIsSponsored. +func (mr *MockStateInfoMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockStateInfo)(nil).AssetIsSponsored), assetID) +} + +// Block mocks base method. +func (m *MockStateInfo) Block(blockID proto.BlockID) (*proto.Block, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Block", blockID) + ret0, _ := ret[0].(*proto.Block) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Block indicates an expected call of Block. +func (mr *MockStateInfoMockRecorder) Block(blockID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockStateInfo)(nil).Block), blockID) +} + +// BlockByHeight mocks base method. +func (m *MockStateInfo) BlockByHeight(height proto.Height) (*proto.Block, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockByHeight", height) + ret0, _ := ret[0].(*proto.Block) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BlockByHeight indicates an expected call of BlockByHeight. +func (mr *MockStateInfoMockRecorder) BlockByHeight(height interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockStateInfo)(nil).BlockByHeight), height) } -// BlockIDToHeight mocks base method +// BlockIDToHeight mocks base method. func (m *MockStateInfo) BlockIDToHeight(blockID proto.BlockID) (proto.Height, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockIDToHeight", blockID) @@ -214,43 +262,43 @@ func (m *MockStateInfo) BlockIDToHeight(blockID proto.BlockID) (proto.Height, er return ret0, ret1 } -// BlockIDToHeight indicates an expected call of BlockIDToHeight +// BlockIDToHeight indicates an expected call of BlockIDToHeight. func (mr *MockStateInfoMockRecorder) BlockIDToHeight(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockIDToHeight", reflect.TypeOf((*MockStateInfo)(nil).BlockIDToHeight), blockID) } -// HeightToBlockID mocks base method -func (m *MockStateInfo) HeightToBlockID(height proto.Height) (proto.BlockID, error) { +// BlockchainSettings mocks base method. +func (m *MockStateInfo) BlockchainSettings() (*settings.BlockchainSettings, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeightToBlockID", height) - ret0, _ := ret[0].(proto.BlockID) + ret := m.ctrl.Call(m, "BlockchainSettings") + ret0, _ := ret[0].(*settings.BlockchainSettings) ret1, _ := ret[1].(error) return ret0, ret1 } -// HeightToBlockID indicates an expected call of HeightToBlockID -func (mr *MockStateInfoMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { +// BlockchainSettings indicates an expected call of BlockchainSettings. +func (mr *MockStateInfoMockRecorder) BlockchainSettings() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockStateInfo)(nil).HeightToBlockID), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainSettings", reflect.TypeOf((*MockStateInfo)(nil).BlockchainSettings)) } -// FullWavesBalance mocks base method -func (m *MockStateInfo) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { +// CurrentScore mocks base method. +func (m *MockStateInfo) CurrentScore() (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullWavesBalance", account) - ret0, _ := ret[0].(*proto.FullWavesBalance) + ret := m.ctrl.Call(m, "CurrentScore") + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// FullWavesBalance indicates an expected call of FullWavesBalance -func (mr *MockStateInfoMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { +// CurrentScore indicates an expected call of CurrentScore. +func (mr *MockStateInfoMockRecorder) CurrentScore() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockStateInfo)(nil).FullWavesBalance), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockStateInfo)(nil).CurrentScore)) } -// EffectiveBalance mocks base method +// EffectiveBalance mocks base method. func (m *MockStateInfo) EffectiveBalance(account proto.Recipient, startHeight, endHeight proto.Height) (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EffectiveBalance", account, startHeight, endHeight) @@ -259,133 +307,148 @@ func (m *MockStateInfo) EffectiveBalance(account proto.Recipient, startHeight, e return ret0, ret1 } -// EffectiveBalance indicates an expected call of EffectiveBalance +// EffectiveBalance indicates an expected call of EffectiveBalance. func (mr *MockStateInfoMockRecorder) EffectiveBalance(account, startHeight, endHeight interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EffectiveBalance", reflect.TypeOf((*MockStateInfo)(nil).EffectiveBalance), account, startHeight, endHeight) } -// AccountBalance mocks base method -func (m *MockStateInfo) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { +// EstimatorVersion mocks base method. +func (m *MockStateInfo) EstimatorVersion() (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AccountBalance", account, asset) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "EstimatorVersion") + ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } -// AccountBalance indicates an expected call of AccountBalance -func (mr *MockStateInfoMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { +// EstimatorVersion indicates an expected call of EstimatorVersion. +func (mr *MockStateInfoMockRecorder) EstimatorVersion() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockStateInfo)(nil).AccountBalance), account, asset) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockStateInfo)(nil).EstimatorVersion)) } -// WavesAddressesNumber mocks base method -func (m *MockStateInfo) WavesAddressesNumber() (uint64, error) { +// FullAssetInfo mocks base method. +func (m *MockStateInfo) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WavesAddressesNumber") - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "FullAssetInfo", assetID) + ret0, _ := ret[0].(*proto.FullAssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// WavesAddressesNumber indicates an expected call of WavesAddressesNumber -func (mr *MockStateInfoMockRecorder) WavesAddressesNumber() *gomock.Call { +// FullAssetInfo indicates an expected call of FullAssetInfo. +func (mr *MockStateInfoMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockStateInfo)(nil).WavesAddressesNumber)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockStateInfo)(nil).FullAssetInfo), assetID) } -// ScoreAtHeight mocks base method -func (m *MockStateInfo) ScoreAtHeight(height proto.Height) (*big.Int, error) { +// FullWavesBalance mocks base method. +func (m *MockStateInfo) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScoreAtHeight", height) - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "FullWavesBalance", account) + ret0, _ := ret[0].(*proto.FullWavesBalance) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScoreAtHeight indicates an expected call of ScoreAtHeight -func (mr *MockStateInfoMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { +// FullWavesBalance indicates an expected call of FullWavesBalance. +func (mr *MockStateInfoMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockStateInfo)(nil).ScoreAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockStateInfo)(nil).FullWavesBalance), account) } -// CurrentScore mocks base method -func (m *MockStateInfo) CurrentScore() (*big.Int, error) { +// Header mocks base method. +func (m *MockStateInfo) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CurrentScore") - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "Header", blockID) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// CurrentScore indicates an expected call of CurrentScore -func (mr *MockStateInfoMockRecorder) CurrentScore() *gomock.Call { +// Header indicates an expected call of Header. +func (mr *MockStateInfoMockRecorder) Header(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockStateInfo)(nil).CurrentScore)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockStateInfo)(nil).Header), blockID) } -// BlockchainSettings mocks base method -func (m *MockStateInfo) BlockchainSettings() (*settings.BlockchainSettings, error) { +// HeaderByHeight mocks base method. +func (m *MockStateInfo) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockchainSettings") - ret0, _ := ret[0].(*settings.BlockchainSettings) + ret := m.ctrl.Call(m, "HeaderByHeight", height) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockchainSettings indicates an expected call of BlockchainSettings -func (mr *MockStateInfoMockRecorder) BlockchainSettings() *gomock.Call { +// HeaderByHeight indicates an expected call of HeaderByHeight. +func (mr *MockStateInfoMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainSettings", reflect.TypeOf((*MockStateInfo)(nil).BlockchainSettings)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockStateInfo)(nil).HeaderByHeight), height) } -// Peers mocks base method -func (m *MockStateInfo) Peers() ([]proto.TCPAddr, error) { +// Height mocks base method. +func (m *MockStateInfo) Height() (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Peers") - ret0, _ := ret[0].([]proto.TCPAddr) + ret := m.ctrl.Call(m, "Height") + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// Peers indicates an expected call of Peers -func (mr *MockStateInfoMockRecorder) Peers() *gomock.Call { +// Height indicates an expected call of Height. +func (mr *MockStateInfoMockRecorder) Height() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Peers", reflect.TypeOf((*MockStateInfo)(nil).Peers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockStateInfo)(nil).Height)) } -// VotesNum mocks base method -func (m *MockStateInfo) VotesNum(featureID int16) (uint64, error) { +// HeightToBlockID mocks base method. +func (m *MockStateInfo) HeightToBlockID(height proto.Height) (proto.BlockID, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNum", featureID) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "HeightToBlockID", height) + ret0, _ := ret[0].(proto.BlockID) ret1, _ := ret[1].(error) return ret0, ret1 } -// VotesNum indicates an expected call of VotesNum -func (mr *MockStateInfoMockRecorder) VotesNum(featureID interface{}) *gomock.Call { +// HeightToBlockID indicates an expected call of HeightToBlockID. +func (mr *MockStateInfoMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockStateInfo)(nil).VotesNum), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockStateInfo)(nil).HeightToBlockID), height) } -// VotesNumAtHeight mocks base method -func (m *MockStateInfo) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { +// HitSourceAtHeight mocks base method. +func (m *MockStateInfo) HitSourceAtHeight(height proto.Height) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "HitSourceAtHeight", height) + ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } -// VotesNumAtHeight indicates an expected call of VotesNumAtHeight -func (mr *MockStateInfoMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { +// HitSourceAtHeight indicates an expected call of HitSourceAtHeight. +func (mr *MockStateInfoMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockStateInfo)(nil).VotesNumAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockStateInfo)(nil).HitSourceAtHeight), height) +} + +// InvokeResultByID mocks base method. +func (m *MockStateInfo) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) + ret0, _ := ret[0].(*proto.ScriptResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InvokeResultByID indicates an expected call of InvokeResultByID. +func (mr *MockStateInfoMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockStateInfo)(nil).InvokeResultByID), invokeID) } -// IsActivated mocks base method +// IsActivated mocks base method. func (m *MockStateInfo) IsActivated(featureID int16) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsActivated", featureID) @@ -394,13 +457,13 @@ func (m *MockStateInfo) IsActivated(featureID int16) (bool, error) { return ret0, ret1 } -// IsActivated indicates an expected call of IsActivated +// IsActivated indicates an expected call of IsActivated. func (mr *MockStateInfoMockRecorder) IsActivated(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockStateInfo)(nil).IsActivated), featureID) } -// IsActiveAtHeight mocks base method +// IsActiveAtHeight mocks base method. func (m *MockStateInfo) IsActiveAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsActiveAtHeight", featureID, height) @@ -409,28 +472,28 @@ func (m *MockStateInfo) IsActiveAtHeight(featureID int16, height proto.Height) ( return ret0, ret1 } -// IsActiveAtHeight indicates an expected call of IsActiveAtHeight +// IsActiveAtHeight indicates an expected call of IsActiveAtHeight. func (mr *MockStateInfoMockRecorder) IsActiveAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveAtHeight", reflect.TypeOf((*MockStateInfo)(nil).IsActiveAtHeight), featureID, height) } -// ActivationHeight mocks base method -func (m *MockStateInfo) ActivationHeight(featureID int16) (proto.Height, error) { +// IsActiveLeasing mocks base method. +func (m *MockStateInfo) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ActivationHeight", featureID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// ActivationHeight indicates an expected call of ActivationHeight -func (mr *MockStateInfoMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { +// IsActiveLeasing indicates an expected call of IsActiveLeasing. +func (mr *MockStateInfoMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockStateInfo)(nil).ActivationHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockStateInfo)(nil).IsActiveLeasing), leaseID) } -// IsApproved mocks base method +// IsApproved mocks base method. func (m *MockStateInfo) IsApproved(featureID int16) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsApproved", featureID) @@ -439,13 +502,13 @@ func (m *MockStateInfo) IsApproved(featureID int16) (bool, error) { return ret0, ret1 } -// IsApproved indicates an expected call of IsApproved +// IsApproved indicates an expected call of IsApproved. func (mr *MockStateInfoMockRecorder) IsApproved(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApproved", reflect.TypeOf((*MockStateInfo)(nil).IsApproved), featureID) } -// IsApprovedAtHeight mocks base method +// IsApprovedAtHeight mocks base method. func (m *MockStateInfo) IsApprovedAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsApprovedAtHeight", featureID, height) @@ -454,118 +517,118 @@ func (m *MockStateInfo) IsApprovedAtHeight(featureID int16, height proto.Height) return ret0, ret1 } -// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight +// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight. func (mr *MockStateInfoMockRecorder) IsApprovedAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApprovedAtHeight", reflect.TypeOf((*MockStateInfo)(nil).IsApprovedAtHeight), featureID, height) } -// ApprovalHeight mocks base method -func (m *MockStateInfo) ApprovalHeight(featureID int16) (proto.Height, error) { +// MapR mocks base method. +func (m *MockStateInfo) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ApprovalHeight", featureID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "MapR", arg0) + ret0, _ := ret[0].(interface{}) ret1, _ := ret[1].(error) return ret0, ret1 } -// ApprovalHeight indicates an expected call of ApprovalHeight -func (mr *MockStateInfoMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { +// MapR indicates an expected call of MapR. +func (mr *MockStateInfoMockRecorder) MapR(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockStateInfo)(nil).ApprovalHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockStateInfo)(nil).MapR), arg0) } -// AllFeatures mocks base method -func (m *MockStateInfo) AllFeatures() ([]int16, error) { +// NFTList mocks base method. +func (m *MockStateInfo) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllFeatures") - ret0, _ := ret[0].([]int16) + ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) + ret0, _ := ret[0].([]*proto.FullAssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// AllFeatures indicates an expected call of AllFeatures -func (mr *MockStateInfoMockRecorder) AllFeatures() *gomock.Call { +// NFTList indicates an expected call of NFTList. +func (mr *MockStateInfoMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockStateInfo)(nil).AllFeatures)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockStateInfo)(nil).NFTList), account, limit, afterAssetID) } -// EstimatorVersion mocks base method -func (m *MockStateInfo) EstimatorVersion() (int, error) { +// NewAddrTransactionsIterator mocks base method. +func (m *MockStateInfo) NewAddrTransactionsIterator(addr proto.Address) (state.TransactionIterator, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatorVersion") - ret0, _ := ret[0].(int) + ret := m.ctrl.Call(m, "NewAddrTransactionsIterator", addr) + ret0, _ := ret[0].(state.TransactionIterator) ret1, _ := ret[1].(error) return ret0, ret1 } -// EstimatorVersion indicates an expected call of EstimatorVersion -func (mr *MockStateInfoMockRecorder) EstimatorVersion() *gomock.Call { +// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator. +func (mr *MockStateInfoMockRecorder) NewAddrTransactionsIterator(addr interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockStateInfo)(nil).EstimatorVersion)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddrTransactionsIterator", reflect.TypeOf((*MockStateInfo)(nil).NewAddrTransactionsIterator), addr) } -// AddrByAlias mocks base method -func (m *MockStateInfo) AddrByAlias(alias proto.Alias) (proto.Address, error) { +// Peers mocks base method. +func (m *MockStateInfo) Peers() ([]proto.TCPAddr, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddrByAlias", alias) - ret0, _ := ret[0].(proto.Address) + ret := m.ctrl.Call(m, "Peers") + ret0, _ := ret[0].([]proto.TCPAddr) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddrByAlias indicates an expected call of AddrByAlias -func (mr *MockStateInfoMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { +// Peers indicates an expected call of Peers. +func (mr *MockStateInfoMockRecorder) Peers() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockStateInfo)(nil).AddrByAlias), alias) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Peers", reflect.TypeOf((*MockStateInfo)(nil).Peers)) } -// RetrieveEntries mocks base method -func (m *MockStateInfo) RetrieveEntries(account proto.Recipient) ([]proto.DataEntry, error) { +// ProvidesExtendedApi mocks base method. +func (m *MockStateInfo) ProvidesExtendedApi() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveEntries", account) - ret0, _ := ret[0].([]proto.DataEntry) + ret := m.ctrl.Call(m, "ProvidesExtendedApi") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveEntries indicates an expected call of RetrieveEntries -func (mr *MockStateInfoMockRecorder) RetrieveEntries(account interface{}) *gomock.Call { +// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi. +func (mr *MockStateInfoMockRecorder) ProvidesExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntries", reflect.TypeOf((*MockStateInfo)(nil).RetrieveEntries), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockStateInfo)(nil).ProvidesExtendedApi)) } -// RetrieveEntry mocks base method -func (m *MockStateInfo) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { +// ProvidesStateHashes mocks base method. +func (m *MockStateInfo) ProvidesStateHashes() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveEntry", account, key) - ret0, _ := ret[0].(proto.DataEntry) + ret := m.ctrl.Call(m, "ProvidesStateHashes") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveEntry indicates an expected call of RetrieveEntry -func (mr *MockStateInfoMockRecorder) RetrieveEntry(account, key interface{}) *gomock.Call { +// ProvidesStateHashes indicates an expected call of ProvidesStateHashes. +func (mr *MockStateInfoMockRecorder) ProvidesStateHashes() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockStateInfo)(nil).ProvidesStateHashes)) } -// RetrieveIntegerEntry mocks base method -func (m *MockStateInfo) RetrieveIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { +// RetrieveBinaryEntry mocks base method. +func (m *MockStateInfo) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveIntegerEntry", account, key) - ret0, _ := ret[0].(*proto.IntegerDataEntry) + ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) + ret0, _ := ret[0].(*proto.BinaryDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry -func (mr *MockStateInfoMockRecorder) RetrieveIntegerEntry(account, key interface{}) *gomock.Call { +// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry. +func (mr *MockStateInfoMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveIntegerEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveIntegerEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveBinaryEntry), account, key) } -// RetrieveBooleanEntry mocks base method +// RetrieveBooleanEntry mocks base method. func (m *MockStateInfo) RetrieveBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RetrieveBooleanEntry", account, key) @@ -574,337 +637,290 @@ func (m *MockStateInfo) RetrieveBooleanEntry(account proto.Recipient, key string return ret0, ret1 } -// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry +// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry. func (mr *MockStateInfoMockRecorder) RetrieveBooleanEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBooleanEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveBooleanEntry), account, key) } -// RetrieveStringEntry mocks base method -func (m *MockStateInfo) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { +// RetrieveEntries mocks base method. +func (m *MockStateInfo) RetrieveEntries(account proto.Recipient) ([]proto.DataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) - ret0, _ := ret[0].(*proto.StringDataEntry) + ret := m.ctrl.Call(m, "RetrieveEntries", account) + ret0, _ := ret[0].([]proto.DataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveStringEntry indicates an expected call of RetrieveStringEntry -func (mr *MockStateInfoMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { +// RetrieveEntries indicates an expected call of RetrieveEntries. +func (mr *MockStateInfoMockRecorder) RetrieveEntries(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveStringEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntries", reflect.TypeOf((*MockStateInfo)(nil).RetrieveEntries), account) } -// RetrieveBinaryEntry mocks base method -func (m *MockStateInfo) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { +// RetrieveEntry mocks base method. +func (m *MockStateInfo) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) - ret0, _ := ret[0].(*proto.BinaryDataEntry) + ret := m.ctrl.Call(m, "RetrieveEntry", account, key) + ret0, _ := ret[0].(proto.DataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry -func (mr *MockStateInfoMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { +// RetrieveEntry indicates an expected call of RetrieveEntry. +func (mr *MockStateInfoMockRecorder) RetrieveEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveBinaryEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveEntry), account, key) } -// TransactionByID mocks base method -func (m *MockStateInfo) TransactionByID(id []byte) (proto.Transaction, error) { +// RetrieveIntegerEntry mocks base method. +func (m *MockStateInfo) RetrieveIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionByID", id) - ret0, _ := ret[0].(proto.Transaction) + ret := m.ctrl.Call(m, "RetrieveIntegerEntry", account, key) + ret0, _ := ret[0].(*proto.IntegerDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// TransactionByID indicates an expected call of TransactionByID -func (mr *MockStateInfoMockRecorder) TransactionByID(id interface{}) *gomock.Call { +// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry. +func (mr *MockStateInfoMockRecorder) RetrieveIntegerEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockStateInfo)(nil).TransactionByID), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveIntegerEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveIntegerEntry), account, key) } -// TransactionByIDWithStatus mocks base method -func (m *MockStateInfo) TransactionByIDWithStatus(id []byte) (proto.Transaction, bool, error) { +// RetrieveStringEntry mocks base method. +func (m *MockStateInfo) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionByIDWithStatus", id) - ret0, _ := ret[0].(proto.Transaction) - ret1, _ := ret[1].(bool) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) + ret0, _ := ret[0].(*proto.StringDataEntry) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus -func (mr *MockStateInfoMockRecorder) TransactionByIDWithStatus(id interface{}) *gomock.Call { +// RetrieveStringEntry indicates an expected call of RetrieveStringEntry. +func (mr *MockStateInfoMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByIDWithStatus", reflect.TypeOf((*MockStateInfo)(nil).TransactionByIDWithStatus), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockStateInfo)(nil).RetrieveStringEntry), account, key) } -// TransactionHeightByID mocks base method -func (m *MockStateInfo) TransactionHeightByID(id []byte) (uint64, error) { +// ScoreAtHeight mocks base method. +func (m *MockStateInfo) ScoreAtHeight(height proto.Height) (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionHeightByID", id) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "ScoreAtHeight", height) + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// TransactionHeightByID indicates an expected call of TransactionHeightByID -func (mr *MockStateInfoMockRecorder) TransactionHeightByID(id interface{}) *gomock.Call { +// ScoreAtHeight indicates an expected call of ScoreAtHeight. +func (mr *MockStateInfoMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionHeightByID", reflect.TypeOf((*MockStateInfo)(nil).TransactionHeightByID), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockStateInfo)(nil).ScoreAtHeight), height) } -// NewAddrTransactionsIterator mocks base method -func (m *MockStateInfo) NewAddrTransactionsIterator(addr proto.Address) (state.TransactionIterator, error) { +// ScriptInfoByAccount mocks base method. +func (m *MockStateInfo) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewAddrTransactionsIterator", addr) - ret0, _ := ret[0].(state.TransactionIterator) + ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) + ret0, _ := ret[0].(*proto.ScriptInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator -func (mr *MockStateInfoMockRecorder) NewAddrTransactionsIterator(addr interface{}) *gomock.Call { +// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount. +func (mr *MockStateInfoMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddrTransactionsIterator", reflect.TypeOf((*MockStateInfo)(nil).NewAddrTransactionsIterator), addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAccount), account) } -// AssetIsSponsored mocks base method -func (m *MockStateInfo) AssetIsSponsored(assetID crypto.Digest) (bool, error) { +// ScriptInfoByAsset mocks base method. +func (m *MockStateInfo) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) + ret0, _ := ret[0].(*proto.ScriptInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssetIsSponsored indicates an expected call of AssetIsSponsored -func (mr *MockStateInfoMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { +// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset. +func (mr *MockStateInfoMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockStateInfo)(nil).AssetIsSponsored), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAsset), assetID) } -// AssetInfo mocks base method -func (m *MockStateInfo) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { +// ShouldPersistAddressTransactions mocks base method. +func (m *MockStateInfo) ShouldPersistAddressTransactions() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetInfo", assetID) - ret0, _ := ret[0].(*proto.AssetInfo) + ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssetInfo indicates an expected call of AssetInfo -func (mr *MockStateInfoMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { +// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions. +func (mr *MockStateInfoMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockStateInfo)(nil).AssetInfo), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockStateInfo)(nil).ShouldPersistAddressTransactions)) } -// FullAssetInfo mocks base method -func (m *MockStateInfo) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { +// SmartState mocks base method. +func (m *MockStateInfo) SmartState() types.SmartState { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullAssetInfo", assetID) - ret0, _ := ret[0].(*proto.FullAssetInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "SmartState") + ret0, _ := ret[0].(types.SmartState) + return ret0 } -// FullAssetInfo indicates an expected call of FullAssetInfo -func (mr *MockStateInfoMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { +// SmartState indicates an expected call of SmartState. +func (mr *MockStateInfoMockRecorder) SmartState() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockStateInfo)(nil).FullAssetInfo), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SmartState", reflect.TypeOf((*MockStateInfo)(nil).SmartState)) } -// NFTList mocks base method -func (m *MockStateInfo) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { +// StateHashAtHeight mocks base method. +func (m *MockStateInfo) StateHashAtHeight(height uint64) (*proto.StateHash, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) - ret0, _ := ret[0].([]*proto.FullAssetInfo) + ret := m.ctrl.Call(m, "StateHashAtHeight", height) + ret0, _ := ret[0].(*proto.StateHash) ret1, _ := ret[1].(error) return ret0, ret1 } -// NFTList indicates an expected call of NFTList -func (mr *MockStateInfoMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { +// StateHashAtHeight indicates an expected call of StateHashAtHeight. +func (mr *MockStateInfoMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockStateInfo)(nil).NFTList), account, limit, afterAssetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockStateInfo)(nil).StateHashAtHeight), height) } -// ScriptInfoByAccount mocks base method -func (m *MockStateInfo) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { +// TopBlock mocks base method. +func (m *MockStateInfo) TopBlock() *proto.Block { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) - ret0, _ := ret[0].(*proto.ScriptInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "TopBlock") + ret0, _ := ret[0].(*proto.Block) + return ret0 } -// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount -func (mr *MockStateInfoMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { +// TopBlock indicates an expected call of TopBlock. +func (mr *MockStateInfoMockRecorder) TopBlock() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAccount), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockStateInfo)(nil).TopBlock)) } -// ScriptInfoByAsset mocks base method -func (m *MockStateInfo) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { +// TransactionByID mocks base method. +func (m *MockStateInfo) TransactionByID(id []byte) (proto.Transaction, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) - ret0, _ := ret[0].(*proto.ScriptInfo) + ret := m.ctrl.Call(m, "TransactionByID", id) + ret0, _ := ret[0].(proto.Transaction) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset -func (mr *MockStateInfoMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { +// TransactionByID indicates an expected call of TransactionByID. +func (mr *MockStateInfoMockRecorder) TransactionByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockStateInfo)(nil).ScriptInfoByAsset), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockStateInfo)(nil).TransactionByID), id) } -// IsActiveLeasing mocks base method -func (m *MockStateInfo) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { +// TransactionByIDWithStatus mocks base method. +func (m *MockStateInfo) TransactionByIDWithStatus(id []byte) (proto.Transaction, bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "TransactionByIDWithStatus", id) + ret0, _ := ret[0].(proto.Transaction) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } -// IsActiveLeasing indicates an expected call of IsActiveLeasing -func (mr *MockStateInfoMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { +// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus. +func (mr *MockStateInfoMockRecorder) TransactionByIDWithStatus(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockStateInfo)(nil).IsActiveLeasing), leaseID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByIDWithStatus", reflect.TypeOf((*MockStateInfo)(nil).TransactionByIDWithStatus), id) } -// InvokeResultByID mocks base method -func (m *MockStateInfo) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { +// TransactionHeightByID mocks base method. +func (m *MockStateInfo) TransactionHeightByID(id []byte) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) - ret0, _ := ret[0].(*proto.ScriptResult) + ret := m.ctrl.Call(m, "TransactionHeightByID", id) + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// InvokeResultByID indicates an expected call of InvokeResultByID -func (mr *MockStateInfoMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { +// TransactionHeightByID indicates an expected call of TransactionHeightByID. +func (mr *MockStateInfoMockRecorder) TransactionHeightByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockStateInfo)(nil).InvokeResultByID), invokeID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionHeightByID", reflect.TypeOf((*MockStateInfo)(nil).TransactionHeightByID), id) } -// ProvidesExtendedApi mocks base method -func (m *MockStateInfo) ProvidesExtendedApi() (bool, error) { +// VotesNum mocks base method. +func (m *MockStateInfo) VotesNum(featureID int16) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesExtendedApi") - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "VotesNum", featureID) + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi -func (mr *MockStateInfoMockRecorder) ProvidesExtendedApi() *gomock.Call { +// VotesNum indicates an expected call of VotesNum. +func (mr *MockStateInfoMockRecorder) VotesNum(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockStateInfo)(nil).ProvidesExtendedApi)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockStateInfo)(nil).VotesNum), featureID) } -// ProvidesStateHashes mocks base method -func (m *MockStateInfo) ProvidesStateHashes() (bool, error) { +// VotesNumAtHeight mocks base method. +func (m *MockStateInfo) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesStateHashes") - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// ProvidesStateHashes indicates an expected call of ProvidesStateHashes -func (mr *MockStateInfoMockRecorder) ProvidesStateHashes() *gomock.Call { +// VotesNumAtHeight indicates an expected call of VotesNumAtHeight. +func (mr *MockStateInfoMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockStateInfo)(nil).ProvidesStateHashes)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockStateInfo)(nil).VotesNumAtHeight), featureID, height) } -// StateHashAtHeight mocks base method -func (m *MockStateInfo) StateHashAtHeight(height uint64) (*proto.StateHash, error) { +// WavesAddressesNumber mocks base method. +func (m *MockStateInfo) WavesAddressesNumber() (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateHashAtHeight", height) - ret0, _ := ret[0].(*proto.StateHash) + ret := m.ctrl.Call(m, "WavesAddressesNumber") + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// StateHashAtHeight indicates an expected call of StateHashAtHeight -func (mr *MockStateInfoMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { +// WavesAddressesNumber indicates an expected call of WavesAddressesNumber. +func (mr *MockStateInfoMockRecorder) WavesAddressesNumber() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockStateInfo)(nil).StateHashAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockStateInfo)(nil).WavesAddressesNumber)) } -// MapR mocks base method -func (m *MockStateInfo) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MapR", arg0) - ret0, _ := ret[0].(interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// MapR indicates an expected call of MapR -func (mr *MockStateInfoMockRecorder) MapR(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockStateInfo)(nil).MapR), arg0) -} - -// HitSourceAtHeight mocks base method -func (m *MockStateInfo) HitSourceAtHeight(height proto.Height) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HitSourceAtHeight", height) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// HitSourceAtHeight indicates an expected call of HitSourceAtHeight -func (mr *MockStateInfoMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockStateInfo)(nil).HitSourceAtHeight), height) -} - -// ShouldPersistAddressTransactions mocks base method -func (m *MockStateInfo) ShouldPersistAddressTransactions() (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions -func (mr *MockStateInfoMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockStateInfo)(nil).ShouldPersistAddressTransactions)) -} - -// MockStateModifier is a mock of StateModifier interface +// MockStateModifier is a mock of StateModifier interface. type MockStateModifier struct { ctrl *gomock.Controller recorder *MockStateModifierMockRecorder } -// MockStateModifierMockRecorder is the mock recorder for MockStateModifier +// MockStateModifierMockRecorder is the mock recorder for MockStateModifier. type MockStateModifierMockRecorder struct { mock *MockStateModifier } -// NewMockStateModifier creates a new mock instance +// NewMockStateModifier creates a new mock instance. func NewMockStateModifier(ctrl *gomock.Controller) *MockStateModifier { mock := &MockStateModifier{ctrl: ctrl} mock.recorder = &MockStateModifierMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockStateModifier) EXPECT() *MockStateModifierMockRecorder { return m.recorder } -// AddBlock mocks base method +// AddBlock mocks base method. func (m *MockStateModifier) AddBlock(block []byte) (*proto.Block, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddBlock", block) @@ -913,13 +929,13 @@ func (m *MockStateModifier) AddBlock(block []byte) (*proto.Block, error) { return ret0, ret1 } -// AddBlock indicates an expected call of AddBlock +// AddBlock indicates an expected call of AddBlock. func (mr *MockStateModifierMockRecorder) AddBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBlock", reflect.TypeOf((*MockStateModifier)(nil).AddBlock), block) } -// AddDeserializedBlock mocks base method +// AddDeserializedBlock mocks base method. func (m *MockStateModifier) AddDeserializedBlock(block *proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddDeserializedBlock", block) @@ -928,13 +944,13 @@ func (m *MockStateModifier) AddDeserializedBlock(block *proto.Block) (*proto.Blo return ret0, ret1 } -// AddDeserializedBlock indicates an expected call of AddDeserializedBlock +// AddDeserializedBlock indicates an expected call of AddDeserializedBlock. func (mr *MockStateModifierMockRecorder) AddDeserializedBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDeserializedBlock", reflect.TypeOf((*MockStateModifier)(nil).AddDeserializedBlock), block) } -// AddNewBlocks mocks base method +// AddNewBlocks mocks base method. func (m *MockStateModifier) AddNewBlocks(blocks [][]byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddNewBlocks", blocks) @@ -942,13 +958,13 @@ func (m *MockStateModifier) AddNewBlocks(blocks [][]byte) error { return ret0 } -// AddNewBlocks indicates an expected call of AddNewBlocks +// AddNewBlocks indicates an expected call of AddNewBlocks. func (mr *MockStateModifierMockRecorder) AddNewBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddNewBlocks), blocks) } -// AddNewDeserializedBlocks mocks base method +// AddNewDeserializedBlocks mocks base method. func (m *MockStateModifier) AddNewDeserializedBlocks(blocks []*proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddNewDeserializedBlocks", blocks) @@ -957,13 +973,13 @@ func (m *MockStateModifier) AddNewDeserializedBlocks(blocks []*proto.Block) (*pr return ret0, ret1 } -// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks +// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks. func (mr *MockStateModifierMockRecorder) AddNewDeserializedBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewDeserializedBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddNewDeserializedBlocks), blocks) } -// AddOldBlocks mocks base method +// AddOldBlocks mocks base method. func (m *MockStateModifier) AddOldBlocks(blocks [][]byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddOldBlocks", blocks) @@ -971,13 +987,13 @@ func (m *MockStateModifier) AddOldBlocks(blocks [][]byte) error { return ret0 } -// AddOldBlocks indicates an expected call of AddOldBlocks +// AddOldBlocks indicates an expected call of AddOldBlocks. func (mr *MockStateModifierMockRecorder) AddOldBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddOldBlocks), blocks) } -// AddOldDeserializedBlocks mocks base method +// AddOldDeserializedBlocks mocks base method. func (m *MockStateModifier) AddOldDeserializedBlocks(blocks []*proto.Block) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddOldDeserializedBlocks", blocks) @@ -985,95 +1001,95 @@ func (m *MockStateModifier) AddOldDeserializedBlocks(blocks []*proto.Block) erro return ret0 } -// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks +// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks. func (mr *MockStateModifierMockRecorder) AddOldDeserializedBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldDeserializedBlocks", reflect.TypeOf((*MockStateModifier)(nil).AddOldDeserializedBlocks), blocks) } -// RollbackToHeight mocks base method -func (m *MockStateModifier) RollbackToHeight(height proto.Height) error { +// Close mocks base method. +func (m *MockStateModifier) Close() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackToHeight", height) + ret := m.ctrl.Call(m, "Close") ret0, _ := ret[0].(error) return ret0 } -// RollbackToHeight indicates an expected call of RollbackToHeight -func (mr *MockStateModifierMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { +// Close indicates an expected call of Close. +func (mr *MockStateModifierMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockStateModifier)(nil).RollbackToHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockStateModifier)(nil).Close)) } -// RollbackTo mocks base method -func (m *MockStateModifier) RollbackTo(removalEdge proto.BlockID) error { +// Map mocks base method. +func (m *MockStateModifier) Map(arg0 func(state.NonThreadSafeState) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackTo", removalEdge) + ret := m.ctrl.Call(m, "Map", arg0) ret0, _ := ret[0].(error) return ret0 } -// RollbackTo indicates an expected call of RollbackTo -func (mr *MockStateModifierMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { +// Map indicates an expected call of Map. +func (mr *MockStateModifierMockRecorder) Map(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockStateModifier)(nil).RollbackTo), removalEdge) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockStateModifier)(nil).Map), arg0) } -// ValidateNextTx mocks base method -func (m *MockStateModifier) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { +// PersistAddressTransactions mocks base method. +func (m *MockStateModifier) PersistAddressTransactions() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) + ret := m.ctrl.Call(m, "PersistAddressTransactions") ret0, _ := ret[0].(error) return ret0 } -// ValidateNextTx indicates an expected call of ValidateNextTx -func (mr *MockStateModifierMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { +// PersistAddressTransactions indicates an expected call of PersistAddressTransactions. +func (mr *MockStateModifierMockRecorder) PersistAddressTransactions() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockStateModifier)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockStateModifier)(nil).PersistAddressTransactions)) } -// ResetValidationList mocks base method +// ResetValidationList mocks base method. func (m *MockStateModifier) ResetValidationList() { m.ctrl.T.Helper() m.ctrl.Call(m, "ResetValidationList") } -// ResetValidationList indicates an expected call of ResetValidationList +// ResetValidationList indicates an expected call of ResetValidationList. func (mr *MockStateModifierMockRecorder) ResetValidationList() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetValidationList", reflect.TypeOf((*MockStateModifier)(nil).ResetValidationList)) } -// TxValidation mocks base method -func (m *MockStateModifier) TxValidation(arg0 func(state.TxValidation) error) error { +// RollbackTo mocks base method. +func (m *MockStateModifier) RollbackTo(removalEdge proto.BlockID) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TxValidation", arg0) + ret := m.ctrl.Call(m, "RollbackTo", removalEdge) ret0, _ := ret[0].(error) return ret0 } -// TxValidation indicates an expected call of TxValidation -func (mr *MockStateModifierMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { +// RollbackTo indicates an expected call of RollbackTo. +func (mr *MockStateModifierMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockStateModifier)(nil).TxValidation), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockStateModifier)(nil).RollbackTo), removalEdge) } -// Map mocks base method -func (m *MockStateModifier) Map(arg0 func(state.NonThreadSafeState) error) error { +// RollbackToHeight mocks base method. +func (m *MockStateModifier) RollbackToHeight(height proto.Height) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Map", arg0) + ret := m.ctrl.Call(m, "RollbackToHeight", height) ret0, _ := ret[0].(error) return ret0 } -// Map indicates an expected call of Map -func (mr *MockStateModifierMockRecorder) Map(arg0 interface{}) *gomock.Call { +// RollbackToHeight indicates an expected call of RollbackToHeight. +func (mr *MockStateModifierMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockStateModifier)(nil).Map), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockStateModifier)(nil).RollbackToHeight), height) } -// SavePeers mocks base method +// SavePeers mocks base method. func (m *MockStateModifier) SavePeers(arg0 []proto.TCPAddr) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SavePeers", arg0) @@ -1081,13 +1097,13 @@ func (m *MockStateModifier) SavePeers(arg0 []proto.TCPAddr) error { return ret0 } -// SavePeers indicates an expected call of SavePeers +// SavePeers indicates an expected call of SavePeers. func (mr *MockStateModifierMockRecorder) SavePeers(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SavePeers", reflect.TypeOf((*MockStateModifier)(nil).SavePeers), arg0) } -// StartProvidingExtendedApi mocks base method +// StartProvidingExtendedApi mocks base method. func (m *MockStateModifier) StartProvidingExtendedApi() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StartProvidingExtendedApi") @@ -1095,64 +1111,64 @@ func (m *MockStateModifier) StartProvidingExtendedApi() error { return ret0 } -// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi +// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi. func (mr *MockStateModifierMockRecorder) StartProvidingExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartProvidingExtendedApi", reflect.TypeOf((*MockStateModifier)(nil).StartProvidingExtendedApi)) } -// PersistAddressTransactions mocks base method -func (m *MockStateModifier) PersistAddressTransactions() error { +// TxValidation mocks base method. +func (m *MockStateModifier) TxValidation(arg0 func(state.TxValidation) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PersistAddressTransactions") + ret := m.ctrl.Call(m, "TxValidation", arg0) ret0, _ := ret[0].(error) return ret0 } -// PersistAddressTransactions indicates an expected call of PersistAddressTransactions -func (mr *MockStateModifierMockRecorder) PersistAddressTransactions() *gomock.Call { +// TxValidation indicates an expected call of TxValidation. +func (mr *MockStateModifierMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockStateModifier)(nil).PersistAddressTransactions)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockStateModifier)(nil).TxValidation), arg0) } -// Close mocks base method -func (m *MockStateModifier) Close() error { +// ValidateNextTx mocks base method. +func (m *MockStateModifier) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Close") + ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) ret0, _ := ret[0].(error) return ret0 } -// Close indicates an expected call of Close -func (mr *MockStateModifierMockRecorder) Close() *gomock.Call { +// ValidateNextTx indicates an expected call of ValidateNextTx. +func (mr *MockStateModifierMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockStateModifier)(nil).Close)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockStateModifier)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) } -// MockTxValidation is a mock of TxValidation interface +// MockTxValidation is a mock of TxValidation interface. type MockTxValidation struct { ctrl *gomock.Controller recorder *MockTxValidationMockRecorder } -// MockTxValidationMockRecorder is the mock recorder for MockTxValidation +// MockTxValidationMockRecorder is the mock recorder for MockTxValidation. type MockTxValidationMockRecorder struct { mock *MockTxValidation } -// NewMockTxValidation creates a new mock instance +// NewMockTxValidation creates a new mock instance. func NewMockTxValidation(ctrl *gomock.Controller) *MockTxValidation { mock := &MockTxValidation{ctrl: ctrl} mock.recorder = &MockTxValidationMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockTxValidation) EXPECT() *MockTxValidationMockRecorder { return m.recorder } -// ValidateNextTx mocks base method +// ValidateNextTx mocks base method. func (m *MockTxValidation) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) @@ -1160,576 +1176,586 @@ func (m *MockTxValidation) ValidateNextTx(tx proto.Transaction, currentTimestamp return ret0 } -// ValidateNextTx indicates an expected call of ValidateNextTx +// ValidateNextTx indicates an expected call of ValidateNextTx. func (mr *MockTxValidationMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockTxValidation)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) } -// MockState is a mock of State interface +// MockState is a mock of State interface. type MockState struct { ctrl *gomock.Controller recorder *MockStateMockRecorder } -// MockStateMockRecorder is the mock recorder for MockState +// MockStateMockRecorder is the mock recorder for MockState. type MockStateMockRecorder struct { mock *MockState } -// NewMockState creates a new mock instance +// NewMockState creates a new mock instance. func NewMockState(ctrl *gomock.Controller) *MockState { mock := &MockState{ctrl: ctrl} mock.recorder = &MockStateMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockState) EXPECT() *MockStateMockRecorder { return m.recorder } -// TopBlock mocks base method -func (m *MockState) TopBlock() *proto.Block { +// AccountBalance mocks base method. +func (m *MockState) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TopBlock") - ret0, _ := ret[0].(*proto.Block) - return ret0 + ret := m.ctrl.Call(m, "AccountBalance", account, asset) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// TopBlock indicates an expected call of TopBlock -func (mr *MockStateMockRecorder) TopBlock() *gomock.Call { +// AccountBalance indicates an expected call of AccountBalance. +func (mr *MockStateMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockState)(nil).TopBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockState)(nil).AccountBalance), account, asset) } -// Block mocks base method -func (m *MockState) Block(blockID proto.BlockID) (*proto.Block, error) { +// ActivationHeight mocks base method. +func (m *MockState) ActivationHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Block", blockID) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ActivationHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// Block indicates an expected call of Block -func (mr *MockStateMockRecorder) Block(blockID interface{}) *gomock.Call { +// ActivationHeight indicates an expected call of ActivationHeight. +func (mr *MockStateMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockState)(nil).Block), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockState)(nil).ActivationHeight), featureID) } -// BlockByHeight mocks base method -func (m *MockState) BlockByHeight(height proto.Height) (*proto.Block, error) { +// AddBlock mocks base method. +func (m *MockState) AddBlock(block []byte) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByHeight", height) + ret := m.ctrl.Call(m, "AddBlock", block) ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockByHeight indicates an expected call of BlockByHeight -func (mr *MockStateMockRecorder) BlockByHeight(height interface{}) *gomock.Call { +// AddBlock indicates an expected call of AddBlock. +func (mr *MockStateMockRecorder) AddBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockState)(nil).BlockByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBlock", reflect.TypeOf((*MockState)(nil).AddBlock), block) } -// Header mocks base method -func (m *MockState) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { +// AddDeserializedBlock mocks base method. +func (m *MockState) AddDeserializedBlock(block *proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Header", blockID) - ret0, _ := ret[0].(*proto.BlockHeader) + ret := m.ctrl.Call(m, "AddDeserializedBlock", block) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// Header indicates an expected call of Header -func (mr *MockStateMockRecorder) Header(blockID interface{}) *gomock.Call { +// AddDeserializedBlock indicates an expected call of AddDeserializedBlock. +func (mr *MockStateMockRecorder) AddDeserializedBlock(block interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockState)(nil).Header), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDeserializedBlock", reflect.TypeOf((*MockState)(nil).AddDeserializedBlock), block) } -// HeaderByHeight mocks base method -func (m *MockState) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { +// AddNewBlocks mocks base method. +func (m *MockState) AddNewBlocks(blocks [][]byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByHeight", height) - ret0, _ := ret[0].(*proto.BlockHeader) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "AddNewBlocks", blocks) + ret0, _ := ret[0].(error) + return ret0 } -// HeaderByHeight indicates an expected call of HeaderByHeight -func (mr *MockStateMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { +// AddNewBlocks indicates an expected call of AddNewBlocks. +func (mr *MockStateMockRecorder) AddNewBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockState)(nil).HeaderByHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewBlocks", reflect.TypeOf((*MockState)(nil).AddNewBlocks), blocks) } -// Height mocks base method -func (m *MockState) Height() (proto.Height, error) { +// AddNewDeserializedBlocks mocks base method. +func (m *MockState) AddNewDeserializedBlocks(blocks []*proto.Block) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Height") - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "AddNewDeserializedBlocks", blocks) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// Height indicates an expected call of Height -func (mr *MockStateMockRecorder) Height() *gomock.Call { +// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks. +func (mr *MockStateMockRecorder) AddNewDeserializedBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockState)(nil).Height)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddNewDeserializedBlocks), blocks) } -// BlockIDToHeight mocks base method -func (m *MockState) BlockIDToHeight(blockID proto.BlockID) (proto.Height, error) { +// AddOldBlocks mocks base method. +func (m *MockState) AddOldBlocks(blocks [][]byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockIDToHeight", blockID) - ret0, _ := ret[0].(proto.Height) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "AddOldBlocks", blocks) + ret0, _ := ret[0].(error) + return ret0 } -// BlockIDToHeight indicates an expected call of BlockIDToHeight -func (mr *MockStateMockRecorder) BlockIDToHeight(blockID interface{}) *gomock.Call { +// AddOldBlocks indicates an expected call of AddOldBlocks. +func (mr *MockStateMockRecorder) AddOldBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockIDToHeight", reflect.TypeOf((*MockState)(nil).BlockIDToHeight), blockID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldBlocks", reflect.TypeOf((*MockState)(nil).AddOldBlocks), blocks) } -// HeightToBlockID mocks base method -func (m *MockState) HeightToBlockID(height proto.Height) (proto.BlockID, error) { +// AddOldDeserializedBlocks mocks base method. +func (m *MockState) AddOldDeserializedBlocks(blocks []*proto.Block) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeightToBlockID", height) - ret0, _ := ret[0].(proto.BlockID) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "AddOldDeserializedBlocks", blocks) + ret0, _ := ret[0].(error) + return ret0 } -// HeightToBlockID indicates an expected call of HeightToBlockID -func (mr *MockStateMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { +// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks. +func (mr *MockStateMockRecorder) AddOldDeserializedBlocks(blocks interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockState)(nil).HeightToBlockID), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddOldDeserializedBlocks), blocks) } -// FullWavesBalance mocks base method -func (m *MockState) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { +// AddrByAlias mocks base method. +func (m *MockState) AddrByAlias(alias proto.Alias) (proto.Address, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullWavesBalance", account) - ret0, _ := ret[0].(*proto.FullWavesBalance) + ret := m.ctrl.Call(m, "AddrByAlias", alias) + ret0, _ := ret[0].(proto.Address) ret1, _ := ret[1].(error) return ret0, ret1 } -// FullWavesBalance indicates an expected call of FullWavesBalance -func (mr *MockStateMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { +// AddrByAlias indicates an expected call of AddrByAlias. +func (mr *MockStateMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockState)(nil).FullWavesBalance), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockState)(nil).AddrByAlias), alias) } -// EffectiveBalance mocks base method -func (m *MockState) EffectiveBalance(account proto.Recipient, startHeight, endHeight proto.Height) (uint64, error) { +// AllFeatures mocks base method. +func (m *MockState) AllFeatures() ([]int16, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EffectiveBalance", account, startHeight, endHeight) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "AllFeatures") + ret0, _ := ret[0].([]int16) ret1, _ := ret[1].(error) return ret0, ret1 } -// EffectiveBalance indicates an expected call of EffectiveBalance -func (mr *MockStateMockRecorder) EffectiveBalance(account, startHeight, endHeight interface{}) *gomock.Call { +// AllFeatures indicates an expected call of AllFeatures. +func (mr *MockStateMockRecorder) AllFeatures() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EffectiveBalance", reflect.TypeOf((*MockState)(nil).EffectiveBalance), account, startHeight, endHeight) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockState)(nil).AllFeatures)) } -// AccountBalance mocks base method -func (m *MockState) AccountBalance(account proto.Recipient, asset []byte) (uint64, error) { +// ApprovalHeight mocks base method. +func (m *MockState) ApprovalHeight(featureID int16) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AccountBalance", account, asset) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "ApprovalHeight", featureID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// AccountBalance indicates an expected call of AccountBalance -func (mr *MockStateMockRecorder) AccountBalance(account, asset interface{}) *gomock.Call { +// ApprovalHeight indicates an expected call of ApprovalHeight. +func (mr *MockStateMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountBalance", reflect.TypeOf((*MockState)(nil).AccountBalance), account, asset) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockState)(nil).ApprovalHeight), featureID) } -// WavesAddressesNumber mocks base method -func (m *MockState) WavesAddressesNumber() (uint64, error) { +// AssetInfo mocks base method. +func (m *MockState) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WavesAddressesNumber") - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "AssetInfo", assetID) + ret0, _ := ret[0].(*proto.AssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// WavesAddressesNumber indicates an expected call of WavesAddressesNumber -func (mr *MockStateMockRecorder) WavesAddressesNumber() *gomock.Call { +// AssetInfo indicates an expected call of AssetInfo. +func (mr *MockStateMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockState)(nil).WavesAddressesNumber)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockState)(nil).AssetInfo), assetID) } -// ScoreAtHeight mocks base method -func (m *MockState) ScoreAtHeight(height proto.Height) (*big.Int, error) { +// AssetIsSponsored mocks base method. +func (m *MockState) AssetIsSponsored(assetID crypto.Digest) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScoreAtHeight", height) - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScoreAtHeight indicates an expected call of ScoreAtHeight -func (mr *MockStateMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { +// AssetIsSponsored indicates an expected call of AssetIsSponsored. +func (mr *MockStateMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockState)(nil).ScoreAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockState)(nil).AssetIsSponsored), assetID) } -// CurrentScore mocks base method -func (m *MockState) CurrentScore() (*big.Int, error) { +// Block mocks base method. +func (m *MockState) Block(blockID proto.BlockID) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CurrentScore") - ret0, _ := ret[0].(*big.Int) + ret := m.ctrl.Call(m, "Block", blockID) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// CurrentScore indicates an expected call of CurrentScore -func (mr *MockStateMockRecorder) CurrentScore() *gomock.Call { +// Block indicates an expected call of Block. +func (mr *MockStateMockRecorder) Block(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockState)(nil).CurrentScore)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Block", reflect.TypeOf((*MockState)(nil).Block), blockID) } -// BlockchainSettings mocks base method -func (m *MockState) BlockchainSettings() (*settings.BlockchainSettings, error) { +// BlockByHeight mocks base method. +func (m *MockState) BlockByHeight(height proto.Height) (*proto.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockchainSettings") - ret0, _ := ret[0].(*settings.BlockchainSettings) + ret := m.ctrl.Call(m, "BlockByHeight", height) + ret0, _ := ret[0].(*proto.Block) ret1, _ := ret[1].(error) return ret0, ret1 } -// BlockchainSettings indicates an expected call of BlockchainSettings -func (mr *MockStateMockRecorder) BlockchainSettings() *gomock.Call { +// BlockByHeight indicates an expected call of BlockByHeight. +func (mr *MockStateMockRecorder) BlockByHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainSettings", reflect.TypeOf((*MockState)(nil).BlockchainSettings)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockState)(nil).BlockByHeight), height) } -// Peers mocks base method -func (m *MockState) Peers() ([]proto.TCPAddr, error) { +// BlockIDToHeight mocks base method. +func (m *MockState) BlockIDToHeight(blockID proto.BlockID) (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Peers") - ret0, _ := ret[0].([]proto.TCPAddr) + ret := m.ctrl.Call(m, "BlockIDToHeight", blockID) + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// Peers indicates an expected call of Peers -func (mr *MockStateMockRecorder) Peers() *gomock.Call { +// BlockIDToHeight indicates an expected call of BlockIDToHeight. +func (mr *MockStateMockRecorder) BlockIDToHeight(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Peers", reflect.TypeOf((*MockState)(nil).Peers)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockIDToHeight", reflect.TypeOf((*MockState)(nil).BlockIDToHeight), blockID) } -// VotesNum mocks base method -func (m *MockState) VotesNum(featureID int16) (uint64, error) { +// BlockchainSettings mocks base method. +func (m *MockState) BlockchainSettings() (*settings.BlockchainSettings, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNum", featureID) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "BlockchainSettings") + ret0, _ := ret[0].(*settings.BlockchainSettings) ret1, _ := ret[1].(error) return ret0, ret1 } -// VotesNum indicates an expected call of VotesNum -func (mr *MockStateMockRecorder) VotesNum(featureID interface{}) *gomock.Call { +// BlockchainSettings indicates an expected call of BlockchainSettings. +func (mr *MockStateMockRecorder) BlockchainSettings() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockState)(nil).VotesNum), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainSettings", reflect.TypeOf((*MockState)(nil).BlockchainSettings)) } -// VotesNumAtHeight mocks base method -func (m *MockState) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { +// Close mocks base method. +func (m *MockState) Close() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) - ret0, _ := ret[0].(uint64) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 } -// VotesNumAtHeight indicates an expected call of VotesNumAtHeight -func (mr *MockStateMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { +// Close indicates an expected call of Close. +func (mr *MockStateMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockState)(nil).VotesNumAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockState)(nil).Close)) } -// IsActivated mocks base method -func (m *MockState) IsActivated(featureID int16) (bool, error) { +// CurrentScore mocks base method. +func (m *MockState) CurrentScore() (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActivated", featureID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "CurrentScore") + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsActivated indicates an expected call of IsActivated -func (mr *MockStateMockRecorder) IsActivated(featureID interface{}) *gomock.Call { +// CurrentScore indicates an expected call of CurrentScore. +func (mr *MockStateMockRecorder) CurrentScore() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockState)(nil).IsActivated), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentScore", reflect.TypeOf((*MockState)(nil).CurrentScore)) } -// IsActiveAtHeight mocks base method -func (m *MockState) IsActiveAtHeight(featureID int16, height proto.Height) (bool, error) { +// EffectiveBalance mocks base method. +func (m *MockState) EffectiveBalance(account proto.Recipient, startHeight, endHeight proto.Height) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActiveAtHeight", featureID, height) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "EffectiveBalance", account, startHeight, endHeight) + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsActiveAtHeight indicates an expected call of IsActiveAtHeight -func (mr *MockStateMockRecorder) IsActiveAtHeight(featureID, height interface{}) *gomock.Call { +// EffectiveBalance indicates an expected call of EffectiveBalance. +func (mr *MockStateMockRecorder) EffectiveBalance(account, startHeight, endHeight interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveAtHeight", reflect.TypeOf((*MockState)(nil).IsActiveAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EffectiveBalance", reflect.TypeOf((*MockState)(nil).EffectiveBalance), account, startHeight, endHeight) } -// ActivationHeight mocks base method -func (m *MockState) ActivationHeight(featureID int16) (proto.Height, error) { +// EstimatorVersion mocks base method. +func (m *MockState) EstimatorVersion() (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ActivationHeight", featureID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "EstimatorVersion") + ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } -// ActivationHeight indicates an expected call of ActivationHeight -func (mr *MockStateMockRecorder) ActivationHeight(featureID interface{}) *gomock.Call { +// EstimatorVersion indicates an expected call of EstimatorVersion. +func (mr *MockStateMockRecorder) EstimatorVersion() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivationHeight", reflect.TypeOf((*MockState)(nil).ActivationHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockState)(nil).EstimatorVersion)) } -// IsApproved mocks base method -func (m *MockState) IsApproved(featureID int16) (bool, error) { +// FullAssetInfo mocks base method. +func (m *MockState) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsApproved", featureID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "FullAssetInfo", assetID) + ret0, _ := ret[0].(*proto.FullAssetInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsApproved indicates an expected call of IsApproved -func (mr *MockStateMockRecorder) IsApproved(featureID interface{}) *gomock.Call { +// FullAssetInfo indicates an expected call of FullAssetInfo. +func (mr *MockStateMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApproved", reflect.TypeOf((*MockState)(nil).IsApproved), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockState)(nil).FullAssetInfo), assetID) } -// IsApprovedAtHeight mocks base method -func (m *MockState) IsApprovedAtHeight(featureID int16, height proto.Height) (bool, error) { +// FullWavesBalance mocks base method. +func (m *MockState) FullWavesBalance(account proto.Recipient) (*proto.FullWavesBalance, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsApprovedAtHeight", featureID, height) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "FullWavesBalance", account) + ret0, _ := ret[0].(*proto.FullWavesBalance) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight -func (mr *MockStateMockRecorder) IsApprovedAtHeight(featureID, height interface{}) *gomock.Call { +// FullWavesBalance indicates an expected call of FullWavesBalance. +func (mr *MockStateMockRecorder) FullWavesBalance(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApprovedAtHeight", reflect.TypeOf((*MockState)(nil).IsApprovedAtHeight), featureID, height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullWavesBalance", reflect.TypeOf((*MockState)(nil).FullWavesBalance), account) } -// ApprovalHeight mocks base method -func (m *MockState) ApprovalHeight(featureID int16) (proto.Height, error) { +// Header mocks base method. +func (m *MockState) Header(blockID proto.BlockID) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ApprovalHeight", featureID) - ret0, _ := ret[0].(proto.Height) + ret := m.ctrl.Call(m, "Header", blockID) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// ApprovalHeight indicates an expected call of ApprovalHeight -func (mr *MockStateMockRecorder) ApprovalHeight(featureID interface{}) *gomock.Call { +// Header indicates an expected call of Header. +func (mr *MockStateMockRecorder) Header(blockID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApprovalHeight", reflect.TypeOf((*MockState)(nil).ApprovalHeight), featureID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockState)(nil).Header), blockID) } -// AllFeatures mocks base method -func (m *MockState) AllFeatures() ([]int16, error) { +// HeaderByHeight mocks base method. +func (m *MockState) HeaderByHeight(height proto.Height) (*proto.BlockHeader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllFeatures") - ret0, _ := ret[0].([]int16) + ret := m.ctrl.Call(m, "HeaderByHeight", height) + ret0, _ := ret[0].(*proto.BlockHeader) ret1, _ := ret[1].(error) return ret0, ret1 } -// AllFeatures indicates an expected call of AllFeatures -func (mr *MockStateMockRecorder) AllFeatures() *gomock.Call { +// HeaderByHeight indicates an expected call of HeaderByHeight. +func (mr *MockStateMockRecorder) HeaderByHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllFeatures", reflect.TypeOf((*MockState)(nil).AllFeatures)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHeight", reflect.TypeOf((*MockState)(nil).HeaderByHeight), height) } -// EstimatorVersion mocks base method -func (m *MockState) EstimatorVersion() (int, error) { +// Height mocks base method. +func (m *MockState) Height() (proto.Height, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatorVersion") - ret0, _ := ret[0].(int) + ret := m.ctrl.Call(m, "Height") + ret0, _ := ret[0].(proto.Height) ret1, _ := ret[1].(error) return ret0, ret1 } -// EstimatorVersion indicates an expected call of EstimatorVersion -func (mr *MockStateMockRecorder) EstimatorVersion() *gomock.Call { +// Height indicates an expected call of Height. +func (mr *MockStateMockRecorder) Height() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatorVersion", reflect.TypeOf((*MockState)(nil).EstimatorVersion)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockState)(nil).Height)) } -// AddrByAlias mocks base method -func (m *MockState) AddrByAlias(alias proto.Alias) (proto.Address, error) { +// HeightToBlockID mocks base method. +func (m *MockState) HeightToBlockID(height proto.Height) (proto.BlockID, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddrByAlias", alias) - ret0, _ := ret[0].(proto.Address) + ret := m.ctrl.Call(m, "HeightToBlockID", height) + ret0, _ := ret[0].(proto.BlockID) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddrByAlias indicates an expected call of AddrByAlias -func (mr *MockStateMockRecorder) AddrByAlias(alias interface{}) *gomock.Call { +// HeightToBlockID indicates an expected call of HeightToBlockID. +func (mr *MockStateMockRecorder) HeightToBlockID(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrByAlias", reflect.TypeOf((*MockState)(nil).AddrByAlias), alias) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeightToBlockID", reflect.TypeOf((*MockState)(nil).HeightToBlockID), height) } -// RetrieveEntries mocks base method -func (m *MockState) RetrieveEntries(account proto.Recipient) ([]proto.DataEntry, error) { +// HitSourceAtHeight mocks base method. +func (m *MockState) HitSourceAtHeight(height proto.Height) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveEntries", account) - ret0, _ := ret[0].([]proto.DataEntry) + ret := m.ctrl.Call(m, "HitSourceAtHeight", height) + ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveEntries indicates an expected call of RetrieveEntries -func (mr *MockStateMockRecorder) RetrieveEntries(account interface{}) *gomock.Call { +// HitSourceAtHeight indicates an expected call of HitSourceAtHeight. +func (mr *MockStateMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntries", reflect.TypeOf((*MockState)(nil).RetrieveEntries), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockState)(nil).HitSourceAtHeight), height) } -// RetrieveEntry mocks base method -func (m *MockState) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { +// InvokeResultByID mocks base method. +func (m *MockState) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveEntry", account, key) - ret0, _ := ret[0].(proto.DataEntry) + ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) + ret0, _ := ret[0].(*proto.ScriptResult) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveEntry indicates an expected call of RetrieveEntry -func (mr *MockStateMockRecorder) RetrieveEntry(account, key interface{}) *gomock.Call { +// InvokeResultByID indicates an expected call of InvokeResultByID. +func (mr *MockStateMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntry", reflect.TypeOf((*MockState)(nil).RetrieveEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockState)(nil).InvokeResultByID), invokeID) } -// RetrieveIntegerEntry mocks base method -func (m *MockState) RetrieveIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { +// IsActivated mocks base method. +func (m *MockState) IsActivated(featureID int16) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveIntegerEntry", account, key) - ret0, _ := ret[0].(*proto.IntegerDataEntry) + ret := m.ctrl.Call(m, "IsActivated", featureID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry -func (mr *MockStateMockRecorder) RetrieveIntegerEntry(account, key interface{}) *gomock.Call { +// IsActivated indicates an expected call of IsActivated. +func (mr *MockStateMockRecorder) IsActivated(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveIntegerEntry", reflect.TypeOf((*MockState)(nil).RetrieveIntegerEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActivated", reflect.TypeOf((*MockState)(nil).IsActivated), featureID) } -// RetrieveBooleanEntry mocks base method -func (m *MockState) RetrieveBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { +// IsActiveAtHeight mocks base method. +func (m *MockState) IsActiveAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveBooleanEntry", account, key) - ret0, _ := ret[0].(*proto.BooleanDataEntry) + ret := m.ctrl.Call(m, "IsActiveAtHeight", featureID, height) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry -func (mr *MockStateMockRecorder) RetrieveBooleanEntry(account, key interface{}) *gomock.Call { +// IsActiveAtHeight indicates an expected call of IsActiveAtHeight. +func (mr *MockStateMockRecorder) IsActiveAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBooleanEntry", reflect.TypeOf((*MockState)(nil).RetrieveBooleanEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveAtHeight", reflect.TypeOf((*MockState)(nil).IsActiveAtHeight), featureID, height) } -// RetrieveStringEntry mocks base method -func (m *MockState) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { +// IsActiveLeasing mocks base method. +func (m *MockState) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) - ret0, _ := ret[0].(*proto.StringDataEntry) + ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveStringEntry indicates an expected call of RetrieveStringEntry -func (mr *MockStateMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { +// IsActiveLeasing indicates an expected call of IsActiveLeasing. +func (mr *MockStateMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockState)(nil).RetrieveStringEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockState)(nil).IsActiveLeasing), leaseID) } -// RetrieveBinaryEntry mocks base method -func (m *MockState) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { +// IsApproved mocks base method. +func (m *MockState) IsApproved(featureID int16) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) - ret0, _ := ret[0].(*proto.BinaryDataEntry) + ret := m.ctrl.Call(m, "IsApproved", featureID) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry -func (mr *MockStateMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { +// IsApproved indicates an expected call of IsApproved. +func (mr *MockStateMockRecorder) IsApproved(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockState)(nil).RetrieveBinaryEntry), account, key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApproved", reflect.TypeOf((*MockState)(nil).IsApproved), featureID) } -// TransactionByID mocks base method -func (m *MockState) TransactionByID(id []byte) (proto.Transaction, error) { +// IsApprovedAtHeight mocks base method. +func (m *MockState) IsApprovedAtHeight(featureID int16, height proto.Height) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionByID", id) - ret0, _ := ret[0].(proto.Transaction) + ret := m.ctrl.Call(m, "IsApprovedAtHeight", featureID, height) + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// TransactionByID indicates an expected call of TransactionByID -func (mr *MockStateMockRecorder) TransactionByID(id interface{}) *gomock.Call { +// IsApprovedAtHeight indicates an expected call of IsApprovedAtHeight. +func (mr *MockStateMockRecorder) IsApprovedAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockState)(nil).TransactionByID), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApprovedAtHeight", reflect.TypeOf((*MockState)(nil).IsApprovedAtHeight), featureID, height) } -// TransactionByIDWithStatus mocks base method -func (m *MockState) TransactionByIDWithStatus(id []byte) (proto.Transaction, bool, error) { +// Map mocks base method. +func (m *MockState) Map(arg0 func(state.NonThreadSafeState) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionByIDWithStatus", id) - ret0, _ := ret[0].(proto.Transaction) - ret1, _ := ret[1].(bool) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret := m.ctrl.Call(m, "Map", arg0) + ret0, _ := ret[0].(error) + return ret0 } -// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus -func (mr *MockStateMockRecorder) TransactionByIDWithStatus(id interface{}) *gomock.Call { +// Map indicates an expected call of Map. +func (mr *MockStateMockRecorder) Map(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByIDWithStatus", reflect.TypeOf((*MockState)(nil).TransactionByIDWithStatus), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockState)(nil).Map), arg0) } -// TransactionHeightByID mocks base method -func (m *MockState) TransactionHeightByID(id []byte) (uint64, error) { +// MapR mocks base method. +func (m *MockState) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransactionHeightByID", id) - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "MapR", arg0) + ret0, _ := ret[0].(interface{}) ret1, _ := ret[1].(error) return ret0, ret1 } -// TransactionHeightByID indicates an expected call of TransactionHeightByID -func (mr *MockStateMockRecorder) TransactionHeightByID(id interface{}) *gomock.Call { +// MapR indicates an expected call of MapR. +func (mr *MockStateMockRecorder) MapR(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionHeightByID", reflect.TypeOf((*MockState)(nil).TransactionHeightByID), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockState)(nil).MapR), arg0) +} + +// NFTList mocks base method. +func (m *MockState) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) + ret0, _ := ret[0].([]*proto.FullAssetInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NFTList indicates an expected call of NFTList. +func (mr *MockStateMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockState)(nil).NFTList), account, limit, afterAssetID) } -// NewAddrTransactionsIterator mocks base method +// NewAddrTransactionsIterator mocks base method. func (m *MockState) NewAddrTransactionsIterator(addr proto.Address) (state.TransactionIterator, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewAddrTransactionsIterator", addr) @@ -1738,443 +1764,447 @@ func (m *MockState) NewAddrTransactionsIterator(addr proto.Address) (state.Trans return ret0, ret1 } -// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator +// NewAddrTransactionsIterator indicates an expected call of NewAddrTransactionsIterator. func (mr *MockStateMockRecorder) NewAddrTransactionsIterator(addr interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddrTransactionsIterator", reflect.TypeOf((*MockState)(nil).NewAddrTransactionsIterator), addr) } -// AssetIsSponsored mocks base method -func (m *MockState) AssetIsSponsored(assetID crypto.Digest) (bool, error) { +// Peers mocks base method. +func (m *MockState) Peers() ([]proto.TCPAddr, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetIsSponsored", assetID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "Peers") + ret0, _ := ret[0].([]proto.TCPAddr) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssetIsSponsored indicates an expected call of AssetIsSponsored -func (mr *MockStateMockRecorder) AssetIsSponsored(assetID interface{}) *gomock.Call { +// Peers indicates an expected call of Peers. +func (mr *MockStateMockRecorder) Peers() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetIsSponsored", reflect.TypeOf((*MockState)(nil).AssetIsSponsored), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Peers", reflect.TypeOf((*MockState)(nil).Peers)) } -// AssetInfo mocks base method -func (m *MockState) AssetInfo(assetID crypto.Digest) (*proto.AssetInfo, error) { +// PersistAddressTransactions mocks base method. +func (m *MockState) PersistAddressTransactions() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AssetInfo", assetID) - ret0, _ := ret[0].(*proto.AssetInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "PersistAddressTransactions") + ret0, _ := ret[0].(error) + return ret0 } -// AssetInfo indicates an expected call of AssetInfo -func (mr *MockStateMockRecorder) AssetInfo(assetID interface{}) *gomock.Call { +// PersistAddressTransactions indicates an expected call of PersistAddressTransactions. +func (mr *MockStateMockRecorder) PersistAddressTransactions() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetInfo", reflect.TypeOf((*MockState)(nil).AssetInfo), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockState)(nil).PersistAddressTransactions)) } -// FullAssetInfo mocks base method -func (m *MockState) FullAssetInfo(assetID crypto.Digest) (*proto.FullAssetInfo, error) { +// ProvidesExtendedApi mocks base method. +func (m *MockState) ProvidesExtendedApi() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FullAssetInfo", assetID) - ret0, _ := ret[0].(*proto.FullAssetInfo) + ret := m.ctrl.Call(m, "ProvidesExtendedApi") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// FullAssetInfo indicates an expected call of FullAssetInfo -func (mr *MockStateMockRecorder) FullAssetInfo(assetID interface{}) *gomock.Call { +// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi. +func (mr *MockStateMockRecorder) ProvidesExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullAssetInfo", reflect.TypeOf((*MockState)(nil).FullAssetInfo), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockState)(nil).ProvidesExtendedApi)) } -// NFTList mocks base method -func (m *MockState) NFTList(account proto.Recipient, limit uint64, afterAssetID []byte) ([]*proto.FullAssetInfo, error) { +// ProvidesStateHashes mocks base method. +func (m *MockState) ProvidesStateHashes() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NFTList", account, limit, afterAssetID) - ret0, _ := ret[0].([]*proto.FullAssetInfo) + ret := m.ctrl.Call(m, "ProvidesStateHashes") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// NFTList indicates an expected call of NFTList -func (mr *MockStateMockRecorder) NFTList(account, limit, afterAssetID interface{}) *gomock.Call { +// ProvidesStateHashes indicates an expected call of ProvidesStateHashes. +func (mr *MockStateMockRecorder) ProvidesStateHashes() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NFTList", reflect.TypeOf((*MockState)(nil).NFTList), account, limit, afterAssetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockState)(nil).ProvidesStateHashes)) } -// ScriptInfoByAccount mocks base method -func (m *MockState) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { +// ResetValidationList mocks base method. +func (m *MockState) ResetValidationList() { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) - ret0, _ := ret[0].(*proto.ScriptInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 + m.ctrl.Call(m, "ResetValidationList") } -// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount -func (mr *MockStateMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { +// ResetValidationList indicates an expected call of ResetValidationList. +func (mr *MockStateMockRecorder) ResetValidationList() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockState)(nil).ScriptInfoByAccount), account) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetValidationList", reflect.TypeOf((*MockState)(nil).ResetValidationList)) } -// ScriptInfoByAsset mocks base method -func (m *MockState) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { +// RetrieveBinaryEntry mocks base method. +func (m *MockState) RetrieveBinaryEntry(account proto.Recipient, key string) (*proto.BinaryDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) - ret0, _ := ret[0].(*proto.ScriptInfo) + ret := m.ctrl.Call(m, "RetrieveBinaryEntry", account, key) + ret0, _ := ret[0].(*proto.BinaryDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset -func (mr *MockStateMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { +// RetrieveBinaryEntry indicates an expected call of RetrieveBinaryEntry. +func (mr *MockStateMockRecorder) RetrieveBinaryEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockState)(nil).ScriptInfoByAsset), assetID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBinaryEntry", reflect.TypeOf((*MockState)(nil).RetrieveBinaryEntry), account, key) } -// IsActiveLeasing mocks base method -func (m *MockState) IsActiveLeasing(leaseID crypto.Digest) (bool, error) { +// RetrieveBooleanEntry mocks base method. +func (m *MockState) RetrieveBooleanEntry(account proto.Recipient, key string) (*proto.BooleanDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsActiveLeasing", leaseID) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "RetrieveBooleanEntry", account, key) + ret0, _ := ret[0].(*proto.BooleanDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// IsActiveLeasing indicates an expected call of IsActiveLeasing -func (mr *MockStateMockRecorder) IsActiveLeasing(leaseID interface{}) *gomock.Call { +// RetrieveBooleanEntry indicates an expected call of RetrieveBooleanEntry. +func (mr *MockStateMockRecorder) RetrieveBooleanEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsActiveLeasing", reflect.TypeOf((*MockState)(nil).IsActiveLeasing), leaseID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveBooleanEntry", reflect.TypeOf((*MockState)(nil).RetrieveBooleanEntry), account, key) } -// InvokeResultByID mocks base method -func (m *MockState) InvokeResultByID(invokeID crypto.Digest) (*proto.ScriptResult, error) { +// RetrieveEntries mocks base method. +func (m *MockState) RetrieveEntries(account proto.Recipient) ([]proto.DataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvokeResultByID", invokeID) - ret0, _ := ret[0].(*proto.ScriptResult) + ret := m.ctrl.Call(m, "RetrieveEntries", account) + ret0, _ := ret[0].([]proto.DataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// InvokeResultByID indicates an expected call of InvokeResultByID -func (mr *MockStateMockRecorder) InvokeResultByID(invokeID interface{}) *gomock.Call { +// RetrieveEntries indicates an expected call of RetrieveEntries. +func (mr *MockStateMockRecorder) RetrieveEntries(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvokeResultByID", reflect.TypeOf((*MockState)(nil).InvokeResultByID), invokeID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntries", reflect.TypeOf((*MockState)(nil).RetrieveEntries), account) } -// ProvidesExtendedApi mocks base method -func (m *MockState) ProvidesExtendedApi() (bool, error) { +// RetrieveEntry mocks base method. +func (m *MockState) RetrieveEntry(account proto.Recipient, key string) (proto.DataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesExtendedApi") - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "RetrieveEntry", account, key) + ret0, _ := ret[0].(proto.DataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// ProvidesExtendedApi indicates an expected call of ProvidesExtendedApi -func (mr *MockStateMockRecorder) ProvidesExtendedApi() *gomock.Call { +// RetrieveEntry indicates an expected call of RetrieveEntry. +func (mr *MockStateMockRecorder) RetrieveEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesExtendedApi", reflect.TypeOf((*MockState)(nil).ProvidesExtendedApi)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveEntry", reflect.TypeOf((*MockState)(nil).RetrieveEntry), account, key) } -// ProvidesStateHashes mocks base method -func (m *MockState) ProvidesStateHashes() (bool, error) { +// RetrieveIntegerEntry mocks base method. +func (m *MockState) RetrieveIntegerEntry(account proto.Recipient, key string) (*proto.IntegerDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProvidesStateHashes") - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "RetrieveIntegerEntry", account, key) + ret0, _ := ret[0].(*proto.IntegerDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// ProvidesStateHashes indicates an expected call of ProvidesStateHashes -func (mr *MockStateMockRecorder) ProvidesStateHashes() *gomock.Call { +// RetrieveIntegerEntry indicates an expected call of RetrieveIntegerEntry. +func (mr *MockStateMockRecorder) RetrieveIntegerEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidesStateHashes", reflect.TypeOf((*MockState)(nil).ProvidesStateHashes)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveIntegerEntry", reflect.TypeOf((*MockState)(nil).RetrieveIntegerEntry), account, key) } -// StateHashAtHeight mocks base method -func (m *MockState) StateHashAtHeight(height uint64) (*proto.StateHash, error) { +// RetrieveStringEntry mocks base method. +func (m *MockState) RetrieveStringEntry(account proto.Recipient, key string) (*proto.StringDataEntry, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateHashAtHeight", height) - ret0, _ := ret[0].(*proto.StateHash) + ret := m.ctrl.Call(m, "RetrieveStringEntry", account, key) + ret0, _ := ret[0].(*proto.StringDataEntry) ret1, _ := ret[1].(error) return ret0, ret1 } -// StateHashAtHeight indicates an expected call of StateHashAtHeight -func (mr *MockStateMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { +// RetrieveStringEntry indicates an expected call of RetrieveStringEntry. +func (mr *MockStateMockRecorder) RetrieveStringEntry(account, key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockState)(nil).StateHashAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetrieveStringEntry", reflect.TypeOf((*MockState)(nil).RetrieveStringEntry), account, key) } -// MapR mocks base method -func (m *MockState) MapR(arg0 func(state.StateInfo) (interface{}, error)) (interface{}, error) { +// RollbackTo mocks base method. +func (m *MockState) RollbackTo(removalEdge proto.BlockID) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MapR", arg0) - ret0, _ := ret[0].(interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "RollbackTo", removalEdge) + ret0, _ := ret[0].(error) + return ret0 } -// MapR indicates an expected call of MapR -func (mr *MockStateMockRecorder) MapR(arg0 interface{}) *gomock.Call { +// RollbackTo indicates an expected call of RollbackTo. +func (mr *MockStateMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapR", reflect.TypeOf((*MockState)(nil).MapR), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockState)(nil).RollbackTo), removalEdge) } -// HitSourceAtHeight mocks base method -func (m *MockState) HitSourceAtHeight(height proto.Height) ([]byte, error) { +// RollbackToHeight mocks base method. +func (m *MockState) RollbackToHeight(height proto.Height) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HitSourceAtHeight", height) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "RollbackToHeight", height) + ret0, _ := ret[0].(error) + return ret0 } -// HitSourceAtHeight indicates an expected call of HitSourceAtHeight -func (mr *MockStateMockRecorder) HitSourceAtHeight(height interface{}) *gomock.Call { +// RollbackToHeight indicates an expected call of RollbackToHeight. +func (mr *MockStateMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HitSourceAtHeight", reflect.TypeOf((*MockState)(nil).HitSourceAtHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockState)(nil).RollbackToHeight), height) } -// ShouldPersistAddressTransactions mocks base method -func (m *MockState) ShouldPersistAddressTransactions() (bool, error) { +// SavePeers mocks base method. +func (m *MockState) SavePeers(arg0 []proto.TCPAddr) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "SavePeers", arg0) + ret0, _ := ret[0].(error) + return ret0 } -// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions -func (mr *MockStateMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { +// SavePeers indicates an expected call of SavePeers. +func (mr *MockStateMockRecorder) SavePeers(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockState)(nil).ShouldPersistAddressTransactions)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SavePeers", reflect.TypeOf((*MockState)(nil).SavePeers), arg0) } -// AddBlock mocks base method -func (m *MockState) AddBlock(block []byte) (*proto.Block, error) { +// ScoreAtHeight mocks base method. +func (m *MockState) ScoreAtHeight(height proto.Height) (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddBlock", block) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ScoreAtHeight", height) + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddBlock indicates an expected call of AddBlock -func (mr *MockStateMockRecorder) AddBlock(block interface{}) *gomock.Call { +// ScoreAtHeight indicates an expected call of ScoreAtHeight. +func (mr *MockStateMockRecorder) ScoreAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBlock", reflect.TypeOf((*MockState)(nil).AddBlock), block) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScoreAtHeight", reflect.TypeOf((*MockState)(nil).ScoreAtHeight), height) } -// AddDeserializedBlock mocks base method -func (m *MockState) AddDeserializedBlock(block *proto.Block) (*proto.Block, error) { +// ScriptInfoByAccount mocks base method. +func (m *MockState) ScriptInfoByAccount(account proto.Recipient) (*proto.ScriptInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddDeserializedBlock", block) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ScriptInfoByAccount", account) + ret0, _ := ret[0].(*proto.ScriptInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddDeserializedBlock indicates an expected call of AddDeserializedBlock -func (mr *MockStateMockRecorder) AddDeserializedBlock(block interface{}) *gomock.Call { +// ScriptInfoByAccount indicates an expected call of ScriptInfoByAccount. +func (mr *MockStateMockRecorder) ScriptInfoByAccount(account interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDeserializedBlock", reflect.TypeOf((*MockState)(nil).AddDeserializedBlock), block) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAccount", reflect.TypeOf((*MockState)(nil).ScriptInfoByAccount), account) } -// AddNewBlocks mocks base method -func (m *MockState) AddNewBlocks(blocks [][]byte) error { +// ScriptInfoByAsset mocks base method. +func (m *MockState) ScriptInfoByAsset(assetID crypto.Digest) (*proto.ScriptInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddNewBlocks", blocks) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "ScriptInfoByAsset", assetID) + ret0, _ := ret[0].(*proto.ScriptInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// AddNewBlocks indicates an expected call of AddNewBlocks -func (mr *MockStateMockRecorder) AddNewBlocks(blocks interface{}) *gomock.Call { +// ScriptInfoByAsset indicates an expected call of ScriptInfoByAsset. +func (mr *MockStateMockRecorder) ScriptInfoByAsset(assetID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewBlocks", reflect.TypeOf((*MockState)(nil).AddNewBlocks), blocks) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScriptInfoByAsset", reflect.TypeOf((*MockState)(nil).ScriptInfoByAsset), assetID) } -// AddNewDeserializedBlocks mocks base method -func (m *MockState) AddNewDeserializedBlocks(blocks []*proto.Block) (*proto.Block, error) { +// ShouldPersistAddressTransactions mocks base method. +func (m *MockState) ShouldPersistAddressTransactions() (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddNewDeserializedBlocks", blocks) - ret0, _ := ret[0].(*proto.Block) + ret := m.ctrl.Call(m, "ShouldPersistAddressTransactions") + ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// AddNewDeserializedBlocks indicates an expected call of AddNewDeserializedBlocks -func (mr *MockStateMockRecorder) AddNewDeserializedBlocks(blocks interface{}) *gomock.Call { +// ShouldPersistAddressTransactions indicates an expected call of ShouldPersistAddressTransactions. +func (mr *MockStateMockRecorder) ShouldPersistAddressTransactions() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddNewDeserializedBlocks), blocks) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldPersistAddressTransactions", reflect.TypeOf((*MockState)(nil).ShouldPersistAddressTransactions)) } -// AddOldBlocks mocks base method -func (m *MockState) AddOldBlocks(blocks [][]byte) error { +// SmartState mocks base method. +func (m *MockState) SmartState() types.SmartState { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddOldBlocks", blocks) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "SmartState") + ret0, _ := ret[0].(types.SmartState) return ret0 } -// AddOldBlocks indicates an expected call of AddOldBlocks -func (mr *MockStateMockRecorder) AddOldBlocks(blocks interface{}) *gomock.Call { +// SmartState indicates an expected call of SmartState. +func (mr *MockStateMockRecorder) SmartState() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldBlocks", reflect.TypeOf((*MockState)(nil).AddOldBlocks), blocks) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SmartState", reflect.TypeOf((*MockState)(nil).SmartState)) } -// AddOldDeserializedBlocks mocks base method -func (m *MockState) AddOldDeserializedBlocks(blocks []*proto.Block) error { +// StartProvidingExtendedApi mocks base method. +func (m *MockState) StartProvidingExtendedApi() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddOldDeserializedBlocks", blocks) + ret := m.ctrl.Call(m, "StartProvidingExtendedApi") ret0, _ := ret[0].(error) return ret0 } -// AddOldDeserializedBlocks indicates an expected call of AddOldDeserializedBlocks -func (mr *MockStateMockRecorder) AddOldDeserializedBlocks(blocks interface{}) *gomock.Call { +// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi. +func (mr *MockStateMockRecorder) StartProvidingExtendedApi() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddOldDeserializedBlocks", reflect.TypeOf((*MockState)(nil).AddOldDeserializedBlocks), blocks) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartProvidingExtendedApi", reflect.TypeOf((*MockState)(nil).StartProvidingExtendedApi)) } -// RollbackToHeight mocks base method -func (m *MockState) RollbackToHeight(height proto.Height) error { +// StateHashAtHeight mocks base method. +func (m *MockState) StateHashAtHeight(height uint64) (*proto.StateHash, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackToHeight", height) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "StateHashAtHeight", height) + ret0, _ := ret[0].(*proto.StateHash) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// RollbackToHeight indicates an expected call of RollbackToHeight -func (mr *MockStateMockRecorder) RollbackToHeight(height interface{}) *gomock.Call { +// StateHashAtHeight indicates an expected call of StateHashAtHeight. +func (mr *MockStateMockRecorder) StateHashAtHeight(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToHeight", reflect.TypeOf((*MockState)(nil).RollbackToHeight), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateHashAtHeight", reflect.TypeOf((*MockState)(nil).StateHashAtHeight), height) } -// RollbackTo mocks base method -func (m *MockState) RollbackTo(removalEdge proto.BlockID) error { +// TopBlock mocks base method. +func (m *MockState) TopBlock() *proto.Block { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RollbackTo", removalEdge) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "TopBlock") + ret0, _ := ret[0].(*proto.Block) return ret0 } -// RollbackTo indicates an expected call of RollbackTo -func (mr *MockStateMockRecorder) RollbackTo(removalEdge interface{}) *gomock.Call { +// TopBlock indicates an expected call of TopBlock. +func (mr *MockStateMockRecorder) TopBlock() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTo", reflect.TypeOf((*MockState)(nil).RollbackTo), removalEdge) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TopBlock", reflect.TypeOf((*MockState)(nil).TopBlock)) } -// ValidateNextTx mocks base method -func (m *MockState) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { +// TransactionByID mocks base method. +func (m *MockState) TransactionByID(id []byte) (proto.Transaction, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "TransactionByID", id) + ret0, _ := ret[0].(proto.Transaction) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// ValidateNextTx indicates an expected call of ValidateNextTx -func (mr *MockStateMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { +// TransactionByID indicates an expected call of TransactionByID. +func (mr *MockStateMockRecorder) TransactionByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockState)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockState)(nil).TransactionByID), id) } -// ResetValidationList mocks base method -func (m *MockState) ResetValidationList() { +// TransactionByIDWithStatus mocks base method. +func (m *MockState) TransactionByIDWithStatus(id []byte) (proto.Transaction, bool, error) { m.ctrl.T.Helper() - m.ctrl.Call(m, "ResetValidationList") + ret := m.ctrl.Call(m, "TransactionByIDWithStatus", id) + ret0, _ := ret[0].(proto.Transaction) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } -// ResetValidationList indicates an expected call of ResetValidationList -func (mr *MockStateMockRecorder) ResetValidationList() *gomock.Call { +// TransactionByIDWithStatus indicates an expected call of TransactionByIDWithStatus. +func (mr *MockStateMockRecorder) TransactionByIDWithStatus(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetValidationList", reflect.TypeOf((*MockState)(nil).ResetValidationList)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByIDWithStatus", reflect.TypeOf((*MockState)(nil).TransactionByIDWithStatus), id) } -// TxValidation mocks base method -func (m *MockState) TxValidation(arg0 func(state.TxValidation) error) error { +// TransactionHeightByID mocks base method. +func (m *MockState) TransactionHeightByID(id []byte) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TxValidation", arg0) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "TransactionHeightByID", id) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// TxValidation indicates an expected call of TxValidation -func (mr *MockStateMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { +// TransactionHeightByID indicates an expected call of TransactionHeightByID. +func (mr *MockStateMockRecorder) TransactionHeightByID(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockState)(nil).TxValidation), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionHeightByID", reflect.TypeOf((*MockState)(nil).TransactionHeightByID), id) } -// Map mocks base method -func (m *MockState) Map(arg0 func(state.NonThreadSafeState) error) error { +// TxValidation mocks base method. +func (m *MockState) TxValidation(arg0 func(state.TxValidation) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Map", arg0) + ret := m.ctrl.Call(m, "TxValidation", arg0) ret0, _ := ret[0].(error) return ret0 } -// Map indicates an expected call of Map -func (mr *MockStateMockRecorder) Map(arg0 interface{}) *gomock.Call { +// TxValidation indicates an expected call of TxValidation. +func (mr *MockStateMockRecorder) TxValidation(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockState)(nil).Map), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxValidation", reflect.TypeOf((*MockState)(nil).TxValidation), arg0) } -// SavePeers mocks base method -func (m *MockState) SavePeers(arg0 []proto.TCPAddr) error { +// ValidateNextTx mocks base method. +func (m *MockState) ValidateNextTx(tx proto.Transaction, currentTimestamp, parentTimestamp uint64, blockVersion proto.BlockVersion, acceptFailed bool) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SavePeers", arg0) + ret := m.ctrl.Call(m, "ValidateNextTx", tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) ret0, _ := ret[0].(error) return ret0 } -// SavePeers indicates an expected call of SavePeers -func (mr *MockStateMockRecorder) SavePeers(arg0 interface{}) *gomock.Call { +// ValidateNextTx indicates an expected call of ValidateNextTx. +func (mr *MockStateMockRecorder) ValidateNextTx(tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SavePeers", reflect.TypeOf((*MockState)(nil).SavePeers), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNextTx", reflect.TypeOf((*MockState)(nil).ValidateNextTx), tx, currentTimestamp, parentTimestamp, blockVersion, acceptFailed) } -// StartProvidingExtendedApi mocks base method -func (m *MockState) StartProvidingExtendedApi() error { +// VotesNum mocks base method. +func (m *MockState) VotesNum(featureID int16) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StartProvidingExtendedApi") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "VotesNum", featureID) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// StartProvidingExtendedApi indicates an expected call of StartProvidingExtendedApi -func (mr *MockStateMockRecorder) StartProvidingExtendedApi() *gomock.Call { +// VotesNum indicates an expected call of VotesNum. +func (mr *MockStateMockRecorder) VotesNum(featureID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartProvidingExtendedApi", reflect.TypeOf((*MockState)(nil).StartProvidingExtendedApi)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNum", reflect.TypeOf((*MockState)(nil).VotesNum), featureID) } -// PersistAddressTransactions mocks base method -func (m *MockState) PersistAddressTransactions() error { +// VotesNumAtHeight mocks base method. +func (m *MockState) VotesNumAtHeight(featureID int16, height proto.Height) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PersistAddressTransactions") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "VotesNumAtHeight", featureID, height) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// PersistAddressTransactions indicates an expected call of PersistAddressTransactions -func (mr *MockStateMockRecorder) PersistAddressTransactions() *gomock.Call { +// VotesNumAtHeight indicates an expected call of VotesNumAtHeight. +func (mr *MockStateMockRecorder) VotesNumAtHeight(featureID, height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PersistAddressTransactions", reflect.TypeOf((*MockState)(nil).PersistAddressTransactions)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VotesNumAtHeight", reflect.TypeOf((*MockState)(nil).VotesNumAtHeight), featureID, height) } -// Close mocks base method -func (m *MockState) Close() error { +// WavesAddressesNumber mocks base method. +func (m *MockState) WavesAddressesNumber() (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Close") - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "WavesAddressesNumber") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// Close indicates an expected call of Close -func (mr *MockStateMockRecorder) Close() *gomock.Call { +// WavesAddressesNumber indicates an expected call of WavesAddressesNumber. +func (mr *MockStateMockRecorder) WavesAddressesNumber() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockState)(nil).Close)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WavesAddressesNumber", reflect.TypeOf((*MockState)(nil).WavesAddressesNumber)) } diff --git a/pkg/node/state_fsm/default_mock.go b/pkg/node/state_fsm/default_mock.go index b7db63e515..fc5cfb53fd 100644 --- a/pkg/node/state_fsm/default_mock.go +++ b/pkg/node/state_fsm/default_mock.go @@ -5,78 +5,79 @@ package state_fsm import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" . "github.com/wavesplatform/gowaves/pkg/p2p/peer" - reflect "reflect" ) -// MockDefault is a mock of Default interface +// MockDefault is a mock of Default interface. type MockDefault struct { ctrl *gomock.Controller recorder *MockDefaultMockRecorder } -// MockDefaultMockRecorder is the mock recorder for MockDefault +// MockDefaultMockRecorder is the mock recorder for MockDefault. type MockDefaultMockRecorder struct { mock *MockDefault } -// NewMockDefault creates a new mock instance +// NewMockDefault creates a new mock instance. func NewMockDefault(ctrl *gomock.Controller) *MockDefault { mock := &MockDefault{ctrl: ctrl} mock.recorder = &MockDefaultMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockDefault) EXPECT() *MockDefaultMockRecorder { return m.recorder } -// Noop mocks base method -func (m *MockDefault) Noop(arg0 FSM) (FSM, Async, error) { +// NewPeer mocks base method. +func (m *MockDefault) NewPeer(fsm FSM, p Peer, info BaseInfo) (FSM, Async, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Noop", arg0) + ret := m.ctrl.Call(m, "NewPeer", fsm, p, info) ret0, _ := ret[0].(FSM) ret1, _ := ret[1].(Async) ret2, _ := ret[2].(error) return ret0, ret1, ret2 } -// Noop indicates an expected call of Noop -func (mr *MockDefaultMockRecorder) Noop(arg0 interface{}) *gomock.Call { +// NewPeer indicates an expected call of NewPeer. +func (mr *MockDefaultMockRecorder) NewPeer(fsm, p, info interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Noop", reflect.TypeOf((*MockDefault)(nil).Noop), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewPeer", reflect.TypeOf((*MockDefault)(nil).NewPeer), fsm, p, info) } -// PeerError mocks base method -func (m *MockDefault) PeerError(fsm FSM, p Peer, baseInfo BaseInfo, arg3 error) (FSM, Async, error) { +// Noop mocks base method. +func (m *MockDefault) Noop(arg0 FSM) (FSM, Async, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PeerError", fsm, p, baseInfo, arg3) + ret := m.ctrl.Call(m, "Noop", arg0) ret0, _ := ret[0].(FSM) ret1, _ := ret[1].(Async) ret2, _ := ret[2].(error) return ret0, ret1, ret2 } -// PeerError indicates an expected call of PeerError -func (mr *MockDefaultMockRecorder) PeerError(fsm, p, baseInfo, arg3 interface{}) *gomock.Call { +// Noop indicates an expected call of Noop. +func (mr *MockDefaultMockRecorder) Noop(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerError", reflect.TypeOf((*MockDefault)(nil).PeerError), fsm, p, baseInfo, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Noop", reflect.TypeOf((*MockDefault)(nil).Noop), arg0) } -// NewPeer mocks base method -func (m *MockDefault) NewPeer(fsm FSM, p Peer, info BaseInfo) (FSM, Async, error) { +// PeerError mocks base method. +func (m *MockDefault) PeerError(fsm FSM, p Peer, baseInfo BaseInfo, arg3 error) (FSM, Async, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewPeer", fsm, p, info) + ret := m.ctrl.Call(m, "PeerError", fsm, p, baseInfo, arg3) ret0, _ := ret[0].(FSM) ret1, _ := ret[1].(Async) ret2, _ := ret[2].(error) return ret0, ret1, ret2 } -// NewPeer indicates an expected call of NewPeer -func (mr *MockDefaultMockRecorder) NewPeer(fsm, p, info interface{}) *gomock.Call { +// PeerError indicates an expected call of PeerError. +func (mr *MockDefaultMockRecorder) PeerError(fsm, p, baseInfo, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewPeer", reflect.TypeOf((*MockDefault)(nil).NewPeer), fsm, p, info) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerError", reflect.TypeOf((*MockDefault)(nil).PeerError), fsm, p, baseInfo, arg3) } From 48d19f8dc543fb268927834bd8b9c5e6eb60b3ef Mon Sep 17 00:00:00 2001 From: esuwu Date: Wed, 7 Apr 2021 12:30:04 +0300 Subject: [PATCH 55/55] Added skip file compiler_heplers --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a247f96a78..d0539555a5 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) @@ -32,7 +32,7 @@ gotest: go test -cover ./... fmtcheck: - @gofmt -l -s $(SOURCE_DIRS) | grep ".*\.go" | grep -v ".*bn254/.*\.go"; if [ "$$?" = "0" ]; then exit 1; fi + @gofmt -l -s $(SOURCE_DIRS) | grep ".*\.go" | grep -v "compiler_helpers.go" | grep -v ".*bn254/.*\.go"; if [ "$$?" = "0" ]; then exit 1; fi mod-clean: go mod tidy