Merge pull request #2719 from nspcc-dev/eval
runtime: implement System.Runtime.LoadScript, fix #2701
This commit is contained in:
commit
389bdfd1b6
35 changed files with 196 additions and 50 deletions
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -4,7 +4,7 @@ go 1.17
|
|||
|
||||
require (
|
||||
github.com/nspcc-dev/neo-go v0.99.5-0.20221108145959-8746d9877eb5
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
github.com/stretchr/testify v1.8.0
|
||||
)
|
||||
|
||||
|
|
|
@ -187,8 +187,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h
|
|||
github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
|
||||
github.com/nspcc-dev/neo-go v0.99.5-0.20221108145959-8746d9877eb5 h1:NCIUxkLRB3ovLzM1lvQA6wBNn8fuY7dQx4cMJKLuaAs=
|
||||
github.com/nspcc-dev/neo-go v0.99.5-0.20221108145959-8746d9877eb5/go.mod h1:aWrWJZBYO+9kYC4+qJXvEjySW1WIyPnrHpmdrzd5mJY=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ=
|
||||
github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4=
|
||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 h1:rpMCoRa7expLc9gMiOP724gz6YSykZzmMALR/CmiwnU=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
2
go.mod
2
go.mod
|
@ -12,7 +12,7 @@ require (
|
|||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/nspcc-dev/dbft v0.0.0-20221020093431-31c1bbdc74f2
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible
|
||||
|
|
4
go.sum
4
go.sum
|
@ -260,8 +260,8 @@ github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
|
|||
github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU=
|
||||
github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg=
|
||||
github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
|
|||
|
||||
go 1.17
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262 h1:UTmSLZw5OpD/JPE1B5Vf98GF0zu2/Hsqq1lGLtStTUE=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff h1:iCNHkQg9mZEoo+Vr6XwmCUTeWHeumwb8tZV1Y43NKqo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
|
|
|
@ -84,6 +84,7 @@ func TestSyscallExecution(t *testing.T) {
|
|||
"runtime.GetScriptContainer": {interopnames.SystemRuntimeGetScriptContainer, nil, false},
|
||||
"runtime.GetTime": {interopnames.SystemRuntimeGetTime, nil, false},
|
||||
"runtime.GetTrigger": {interopnames.SystemRuntimeGetTrigger, nil, false},
|
||||
"runtime.LoadScript": {interopnames.SystemRuntimeLoadScript, []string{b, "0", b}, false},
|
||||
"runtime.Log": {interopnames.SystemRuntimeLog, []string{`"msg"`}, true},
|
||||
"runtime.Notify": {interopnames.SystemRuntimeNotify, []string{`"ev"`, "1"}, true},
|
||||
"runtime.Platform": {interopnames.SystemRuntimePlatform, nil, false},
|
||||
|
|
|
@ -124,7 +124,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
|
|||
if wrapped {
|
||||
ic.DAO = ic.DAO.GetPrivate()
|
||||
}
|
||||
onUnload := func(ctx *vm.Context, commit bool) error {
|
||||
onUnload := func(v *vm.VM, ctx *vm.Context, commit bool) error {
|
||||
if wrapped {
|
||||
if commit {
|
||||
_, err := ic.DAO.Persist()
|
||||
|
@ -136,17 +136,12 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
|
|||
}
|
||||
ic.DAO = baseDAO
|
||||
}
|
||||
if isDynamic && commit {
|
||||
eLen := ctx.Estack().Len()
|
||||
if eLen == 0 && ctx.NumOfReturnVals() == 0 { // No return value and none expected.
|
||||
ic.VM.Context().Estack().PushItem(stackitem.Null{}) // Must use current context stack.
|
||||
} else if eLen > 1 { // 1 or -1 (all) retrun values expected, but only one can be returned.
|
||||
return errors.New("multiple return values in a cross-contract call")
|
||||
} // All other rvcount/stack length mismatches are checked by the VM.
|
||||
}
|
||||
if callFromNative && !commit {
|
||||
return fmt.Errorf("unhandled exception")
|
||||
}
|
||||
if isDynamic {
|
||||
return vm.DynamicOnUnload(v, ctx, commit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, f,
|
||||
|
|
|
@ -27,6 +27,7 @@ const (
|
|||
SystemRuntimeGetScriptContainer = "System.Runtime.GetScriptContainer"
|
||||
SystemRuntimeGetTime = "System.Runtime.GetTime"
|
||||
SystemRuntimeGetTrigger = "System.Runtime.GetTrigger"
|
||||
SystemRuntimeLoadScript = "System.Runtime.LoadScript"
|
||||
SystemRuntimeLog = "System.Runtime.Log"
|
||||
SystemRuntimeNotify = "System.Runtime.Notify"
|
||||
SystemRuntimePlatform = "System.Runtime.Platform"
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -105,6 +107,27 @@ func Notify(ic *interop.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// LoadScript takes a script and arguments from the stack and loads it into the VM.
|
||||
func LoadScript(ic *interop.Context) error {
|
||||
script := ic.VM.Estack().Pop().Bytes()
|
||||
fs := callflag.CallFlag(int32(ic.VM.Estack().Pop().BigInt().Int64()))
|
||||
if fs&^callflag.All != 0 {
|
||||
return errors.New("call flags out of range")
|
||||
}
|
||||
args := ic.VM.Estack().Pop().Array()
|
||||
err := vm.IsScriptCorrect(script, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid script: %w", err)
|
||||
}
|
||||
fs = ic.VM.Context().GetCallFlags() & callflag.ReadOnly & fs
|
||||
ic.VM.LoadDynamicScript(script, fs)
|
||||
|
||||
for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- {
|
||||
e.PushItem(args[i])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Log logs the message passed.
|
||||
func Log(ic *interop.Context) error {
|
||||
state := ic.VM.Estack().Pop().String()
|
||||
|
|
|
@ -80,6 +80,28 @@ func loadScriptWithHashAndFlags(ic *interop.Context, script []byte, hash util.Ui
|
|||
ic.VM.GasLimit = -1
|
||||
}
|
||||
|
||||
func wrapDynamicScript(t *testing.T, script []byte, flags callflag.CallFlag, args ...interface{}) []byte {
|
||||
b := io.NewBufBinWriter()
|
||||
|
||||
// Params.
|
||||
emit.Array(b.BinWriter, args...)
|
||||
emit.Int(b.BinWriter, int64(flags))
|
||||
emit.Bytes(b.BinWriter, script)
|
||||
|
||||
// Wrapped syscall.
|
||||
emit.Instruction(b.BinWriter, opcode.TRY, []byte{3 + 5 + 2, 0}) // 3
|
||||
emit.Syscall(b.BinWriter, interopnames.SystemRuntimeLoadScript) // 5
|
||||
emit.Instruction(b.BinWriter, opcode.ENDTRY, []byte{1 + 11 + 2}) // 2
|
||||
|
||||
// Catch block
|
||||
emit.Opcodes(b.BinWriter, opcode.DROP)
|
||||
emit.String(b.BinWriter, "exception") // 1 + 1 + 9 == 11 bytes
|
||||
emit.Opcodes(b.BinWriter, opcode.RET)
|
||||
|
||||
require.NoError(t, b.Err)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func getDeployedInternal(t *testing.T) (*neotest.Executor, neotest.Signer, *core.Blockchain, *state.Contract) {
|
||||
bc, acc := chain.NewSingle(t)
|
||||
e := neotest.NewExecutor(t, bc, acc, acc)
|
||||
|
@ -377,6 +399,66 @@ func TestCheckWitness(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestLoadScript(t *testing.T) {
|
||||
bc, acc := chain.NewSingle(t)
|
||||
e := neotest.NewExecutor(t, bc, acc, acc)
|
||||
|
||||
t.Run("no ret val", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{byte(opcode.RET)}, callflag.All)
|
||||
e.InvokeScriptCheckHALT(t, script, []neotest.Signer{acc}, stackitem.Null{})
|
||||
})
|
||||
t.Run("empty script", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{}, callflag.All)
|
||||
e.InvokeScriptCheckHALT(t, script, []neotest.Signer{acc}, stackitem.Null{})
|
||||
})
|
||||
t.Run("bad script", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{0xff}, callflag.All)
|
||||
e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "invalid script")
|
||||
})
|
||||
t.Run("ret val, no params", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{byte(opcode.PUSH1)}, callflag.All)
|
||||
e.InvokeScriptCheckHALT(t, script, []neotest.Signer{acc}, stackitem.Make(1))
|
||||
})
|
||||
t.Run("ret val with params", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{byte(opcode.MUL)}, callflag.All, 2, 2)
|
||||
e.InvokeScriptCheckHALT(t, script, []neotest.Signer{acc}, stackitem.Make(4))
|
||||
})
|
||||
t.Run("two retrun values", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{byte(opcode.PUSH1), byte(opcode.PUSH1)}, callflag.All, 2, 2)
|
||||
e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "multiple return values in a cross-contract call")
|
||||
})
|
||||
t.Run("invalid flags", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{byte(opcode.MUL)}, callflag.CallFlag(0xff), 2, 2)
|
||||
e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "call flags out of range")
|
||||
})
|
||||
t.Run("abort", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{byte(opcode.ABORT)}, callflag.All)
|
||||
e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "ABORT")
|
||||
})
|
||||
t.Run("internal call", func(t *testing.T) {
|
||||
script, err := smartcontract.CreateCallScript(e.NativeHash(t, nativenames.Gas), "decimals")
|
||||
require.NoError(t, err)
|
||||
script = wrapDynamicScript(t, script, callflag.ReadOnly)
|
||||
e.InvokeScriptCheckHALT(t, script, []neotest.Signer{acc}, stackitem.Make(8))
|
||||
})
|
||||
t.Run("forbidden internal call", func(t *testing.T) {
|
||||
script, err := smartcontract.CreateCallScript(e.NativeHash(t, nativenames.Neo), "decimals")
|
||||
require.NoError(t, err)
|
||||
script = wrapDynamicScript(t, script, callflag.ReadStates)
|
||||
e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "missing call flags")
|
||||
})
|
||||
t.Run("internal state-changing call", func(t *testing.T) {
|
||||
script, err := smartcontract.CreateCallScript(e.NativeHash(t, nativenames.Neo), "transfer", acc.ScriptHash(), acc.ScriptHash(), 1, nil)
|
||||
require.NoError(t, err)
|
||||
script = wrapDynamicScript(t, script, callflag.All)
|
||||
e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "missing call flags")
|
||||
})
|
||||
t.Run("exception", func(t *testing.T) {
|
||||
script := wrapDynamicScript(t, []byte{byte(opcode.PUSH1), byte(opcode.THROW)}, callflag.ReadOnly)
|
||||
e.InvokeScriptCheckHALT(t, script, []neotest.Signer{acc}, stackitem.Make("exception"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestGasLeft(t *testing.T) {
|
||||
const runtimeGasLeftPrice = 1 << 4
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ var systemInterops = []interop.Function{
|
|||
{Name: interopnames.SystemRuntimeGetScriptContainer, Func: runtime.GetScriptContainer, Price: 1 << 3},
|
||||
{Name: interopnames.SystemRuntimeGetTime, Func: runtime.GetTime, Price: 1 << 3, RequiredFlags: callflag.ReadStates},
|
||||
{Name: interopnames.SystemRuntimeGetTrigger, Func: runtime.GetTrigger, Price: 1 << 3},
|
||||
{Name: interopnames.SystemRuntimeLoadScript, Func: runtime.LoadScript, Price: 1 << 15, RequiredFlags: callflag.AllowCall,
|
||||
ParamCount: 3},
|
||||
{Name: interopnames.SystemRuntimeLog, Func: runtime.Log, Price: 1 << 15, RequiredFlags: callflag.AllowNotify,
|
||||
ParamCount: 1},
|
||||
{Name: interopnames.SystemRuntimeNotify, Func: runtime.Notify, Price: 1 << 15, RequiredFlags: callflag.AllowNotify,
|
||||
|
|
|
@ -6,6 +6,7 @@ package runtime
|
|||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
|
||||
)
|
||||
|
||||
|
@ -29,6 +30,21 @@ func CheckWitness(hashOrKey []byte) bool {
|
|||
return neogointernal.Syscall1("System.Runtime.CheckWitness", hashOrKey).(bool)
|
||||
}
|
||||
|
||||
// LoadScript loads the given bytecode into the VM and executes it with the
|
||||
// given call flags and arguments. This bytecode is executed as is from byte 0,
|
||||
// it's not a deployed contract that can have methods. The execution context is
|
||||
// limited to read only actions ([contract.ReadOnly]) irrespective of provided
|
||||
// call flags (you can only restrict them further with this option). An item is
|
||||
// always returned from this call, either it's the one returned from the script
|
||||
// (and it can only return one) or it's a Null stack item if the script returns
|
||||
// nothing. Note that this is somewhat similar to [contract.Call], so the
|
||||
// script can ABORT the transaction or THROW an exception, make sure you
|
||||
// appropriately handle exceptions if bytecode comes from untrusted source.
|
||||
// This function uses `System.Runtime.LoadScript` syscall.
|
||||
func LoadScript(script []byte, f contract.CallFlag, args ...interface{}) interface{} {
|
||||
return neogointernal.Syscall3("System.Runtime.LoadScript", script, f, args)
|
||||
}
|
||||
|
||||
// Log instructs VM to log the given message. It's mostly used for debugging
|
||||
// purposes as these messages are not saved anywhere normally and usually are
|
||||
// only visible in the VM logs. This function uses `System.Runtime.Log` syscall.
|
||||
|
|
|
@ -79,10 +79,14 @@ type contextAux struct {
|
|||
}
|
||||
|
||||
// ContextUnloadCallback is a callback method used on context unloading from istack.
|
||||
type ContextUnloadCallback func(ctx *Context, commit bool) error
|
||||
type ContextUnloadCallback func(v *VM, ctx *Context, commit bool) error
|
||||
|
||||
var errNoInstParam = errors.New("failed to read instruction parameter")
|
||||
|
||||
// ErrMultiRet is returned when caller does not expect multiple return values
|
||||
// from callee.
|
||||
var ErrMultiRet = errors.New("multiple return values in a cross-contract call")
|
||||
|
||||
// NewContext returns a new Context object.
|
||||
func NewContext(b []byte) *Context {
|
||||
return NewContextWithParams(b, -1, 0)
|
||||
|
@ -331,3 +335,18 @@ func (c *Context) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
return json.Marshal(aux)
|
||||
}
|
||||
|
||||
// DynamicOnUnload implements OnUnload script for dynamic calls, if no exception
|
||||
// has occurred it checks that the context has exactly 0 (in which case a `Null`
|
||||
// is pushed) or 1 returned value.
|
||||
func DynamicOnUnload(v *VM, ctx *Context, commit bool) error {
|
||||
if commit {
|
||||
eLen := ctx.Estack().Len()
|
||||
if eLen == 0 { // No return value, add one.
|
||||
v.Context().Estack().PushItem(stackitem.Null{}) // Must use current context stack.
|
||||
} else if eLen > 1 { // Only one can be returned.
|
||||
return ErrMultiRet
|
||||
} // One value returned, it's OK.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -303,6 +303,13 @@ func (v *VM) LoadScriptWithFlags(b []byte, f callflag.CallFlag) {
|
|||
v.loadScriptWithCallingHash(b, nil, v.GetCurrentScriptHash(), util.Uint160{}, f, -1, 0, nil)
|
||||
}
|
||||
|
||||
// LoadDynamicScript loads the given script with the given flags. This script is
|
||||
// considered to be dynamic, it can either return no value at all or return
|
||||
// exactly one value.
|
||||
func (v *VM) LoadDynamicScript(b []byte, f callflag.CallFlag) {
|
||||
v.loadScriptWithCallingHash(b, nil, v.GetCurrentScriptHash(), util.Uint160{}, f, -1, 0, DynamicOnUnload)
|
||||
}
|
||||
|
||||
// LoadScriptWithHash is similar to the LoadScriptWithFlags method, but it also loads
|
||||
// the given script hash directly into the Context to avoid its recalculations and to make
|
||||
// it possible to override it for deployed contracts with special hashes (the function
|
||||
|
@ -1641,7 +1648,7 @@ func (v *VM) unloadContext(ctx *Context) {
|
|||
ctx.sc.static.ClearRefs(&v.refs)
|
||||
}
|
||||
if ctx.sc.onUnload != nil {
|
||||
err := ctx.sc.onUnload(ctx, v.uncaughtException == nil)
|
||||
err := ctx.sc.onUnload(v, ctx, v.uncaughtException == nil)
|
||||
if err != nil {
|
||||
errMessage := fmt.Sprintf("context unload callback failed: %s", err)
|
||||
if v.uncaughtException != nil {
|
||||
|
|
Loading…
Reference in a new issue