diff --git a/examples/engine/go.mod b/examples/engine/go.mod index 2c07f1da5..ca36225f2 100644 --- a/examples/engine/go.mod +++ b/examples/engine/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/engine/go.sum b/examples/engine/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/engine/go.sum +++ b/examples/engine/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/events/go.mod b/examples/events/go.mod index bf910ab59..150042660 100644 --- a/examples/events/go.mod +++ b/examples/events/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/events/go.sum b/examples/events/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/events/go.sum +++ b/examples/events/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/iterator/go.mod b/examples/iterator/go.mod index c982826d3..190a851ea 100644 --- a/examples/iterator/go.mod +++ b/examples/iterator/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/iterator/go.sum b/examples/iterator/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/iterator/go.sum +++ b/examples/iterator/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/nft-d/go.mod b/examples/nft-d/go.mod index 7a0cddd29..6d174238b 100644 --- a/examples/nft-d/go.mod +++ b/examples/nft-d/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/nft-d/go.sum b/examples/nft-d/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/nft-d/go.sum +++ b/examples/nft-d/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/nft-d/us.stackdump b/examples/nft-d/us.stackdump new file mode 100644 index 000000000..c504aaf65 --- /dev/null +++ b/examples/nft-d/us.stackdump @@ -0,0 +1,8 @@ +MSYS-1.0.19 Build:2016-07-13 17:45 +Exception: STATUS_ACCESS_VIOLATION at eip=0072174E +eax=608F9138 ebx=00000000 ecx=60EA0000 edx=60EA4184 esi=00993208 edi=00000001 +ebp=0069FEB0 esp=0069FE48 program=us +cs=0023 ds=002B es=002B fs=0053 gs=002B ss=002B +Stack trace: +Frame Function Args + 15750 [main] us 0 handle_exceptions: Error while dumping state (probably corrupted stack) diff --git a/examples/nft-nd-nns/go.mod b/examples/nft-nd-nns/go.mod index 3de7a2453..9ffa0641e 100644 --- a/examples/nft-nd-nns/go.mod +++ b/examples/nft-nd-nns/go.mod @@ -3,7 +3,7 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd-nns go 1.16 require ( - github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220421162730-3463d7292fb9 - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c + github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220429082343-69b70c5e933a + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 github.com/stretchr/testify v1.7.0 ) diff --git a/examples/nft-nd-nns/go.sum b/examples/nft-nd-nns/go.sum index 44a859e5f..759e1af82 100644 --- a/examples/nft-nd-nns/go.sum +++ b/examples/nft-nd-nns/go.sum @@ -177,10 +177,10 @@ 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 v0.98.3-pre.0.20220421162730-3463d7292fb9 h1:hflyJ+EnjaLPXtpxM4Wibqo4ppnfXCjf4kBUzxvp/MU= -github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220421162730-3463d7292fb9/go.mod h1:LGZ16CRv4Nfh7KTt99CH/bhjOlTPQPbJcICJ4onP4Ds= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220429082343-69b70c5e933a h1:5tTKYXxz/DRDopPpf2/2rcdkESDm/RWH3t5aNXyGtAc= +github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220429082343-69b70c5e933a/go.mod h1:hKgAWnSYaq5FIg8XclLvG5gjsjjFMkFhklyO092/sGM= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= 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= diff --git a/examples/nft-nd/go.mod b/examples/nft-nd/go.mod index 9fd7fd8f7..fd970fdd5 100644 --- a/examples/nft-nd/go.mod +++ b/examples/nft-nd/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/nft-nd/go.sum b/examples/nft-nd/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/nft-nd/go.sum +++ b/examples/nft-nd/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/oracle/go.mod b/examples/oracle/go.mod index 8640f8bdb..5022c50c4 100644 --- a/examples/oracle/go.mod +++ b/examples/oracle/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/oracle/go.sum b/examples/oracle/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/oracle/go.sum +++ b/examples/oracle/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/runtime/go.mod b/examples/runtime/go.mod index f5ef78809..34266ef33 100644 --- a/examples/runtime/go.mod +++ b/examples/runtime/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/runtime/go.sum b/examples/runtime/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/runtime/go.sum +++ b/examples/runtime/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/storage/go.mod b/examples/storage/go.mod index 4e83bb0e6..8306fcc07 100644 --- a/examples/storage/go.mod +++ b/examples/storage/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/storage/go.sum b/examples/storage/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/storage/go.sum +++ b/examples/storage/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/timer/go.mod b/examples/timer/go.mod index 71a0b2e8d..5b3b5eac5 100644 --- a/examples/timer/go.mod +++ b/examples/timer/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/timer/go.sum b/examples/timer/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/timer/go.sum +++ b/examples/timer/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/examples/token/go.mod b/examples/token/go.mod index 4d0793cc2..75a5bade7 100644 --- a/examples/token/go.mod +++ b/examples/token/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token go 1.16 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 diff --git a/examples/token/go.sum b/examples/token/go.sum index d8b32c089..b0859f2dd 100644 --- a/examples/token/go.sum +++ b/examples/token/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= diff --git a/go.mod b/go.mod index 3fcdf5c56..e48e33ca8 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/nspcc-dev/dbft v0.0.0-20220414131237-e497bbf7868e github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 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 diff --git a/go.sum b/go.sum index 949627592..0c5851356 100644 --- a/go.sum +++ b/go.sum @@ -185,8 +185,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-20220421162616-d942940a826c h1:D0iDtGEnFbld/tllTbv3ah4BQPPaItTs/Y8Li5zrEOw= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220421162616-d942940a826c/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y= 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= diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go index adf907fc5..e3862b0d5 100644 --- a/pkg/compiler/native_test.go +++ b/pkg/compiler/native_test.go @@ -89,6 +89,32 @@ func TestOracleContractValues(t *testing.T) { require.EqualValues(t, oracle.MinimumResponseGas, native.MinimumResponseGas) } +func TestLedgerTransactionWitnessScope(t *testing.T) { + require.EqualValues(t, ledger.None, transaction.None) + require.EqualValues(t, ledger.CalledByEntry, transaction.CalledByEntry) + require.EqualValues(t, ledger.CustomContracts, transaction.CustomContracts) + require.EqualValues(t, ledger.CustomGroups, transaction.CustomGroups) + require.EqualValues(t, ledger.Rules, transaction.Rules) + require.EqualValues(t, ledger.Global, transaction.Global) +} + +func TestLedgerTransactionWitnessAction(t *testing.T) { + require.EqualValues(t, ledger.WitnessAllow, transaction.WitnessAllow) + require.EqualValues(t, ledger.WitnessDeny, transaction.WitnessDeny) +} + +func TestLedgerTransactionWitnessCondition(t *testing.T) { + require.EqualValues(t, ledger.WitnessBoolean, transaction.WitnessBoolean) + require.EqualValues(t, ledger.WitnessNot, transaction.WitnessNot) + require.EqualValues(t, ledger.WitnessAnd, transaction.WitnessAnd) + require.EqualValues(t, ledger.WitnessOr, transaction.WitnessOr) + require.EqualValues(t, ledger.WitnessScriptHash, transaction.WitnessScriptHash) + require.EqualValues(t, ledger.WitnessGroup, transaction.WitnessGroup) + require.EqualValues(t, ledger.WitnessCalledByEntry, transaction.WitnessCalledByEntry) + require.EqualValues(t, ledger.WitnessCalledByContract, transaction.WitnessCalledByContract) + require.EqualValues(t, ledger.WitnessCalledByGroup, transaction.WitnessCalledByGroup) +} + func TestLedgerVMStates(t *testing.T) { require.EqualValues(t, ledger.NoneState, vm.NoneState) require.EqualValues(t, ledger.HaltState, vm.HaltState) @@ -158,6 +184,7 @@ func TestNativeHelpersCompile(t *testing.T) { {"getTransaction", []string{u256}}, {"getTransactionFromBlock", []string{u256, "1"}}, {"getTransactionHeight", []string{u256}}, + {"getTransactionSigners", []string{u256}}, {"getTransactionVMState", []string{u256}}, }) runNativeTestCases(t, cs.Notary.ContractMD, "notary", []nativeTestCase{ diff --git a/pkg/core/native/ledger.go b/pkg/core/native/ledger.go index e00923a71..64506e506 100644 --- a/pkg/core/native/ledger.go +++ b/pkg/core/native/ledger.go @@ -10,6 +10,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/transaction" + "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" @@ -63,6 +64,11 @@ func newLedger() *Ledger { md = newMethodAndPrice(l.getTransactionFromBlock, 1<<16, callflag.ReadStates) l.AddMethod(md, desc) + desc = newDescriptor("getTransactionSigners", smartcontract.ArrayType, + manifest.NewParameter("hash", smartcontract.Hash256Type)) + md = newMethodAndPrice(l.getTransactionSigners, 1<<15, callflag.ReadStates) + l.AddMethod(md, desc) + desc = newDescriptor("getTransactionVMState", smartcontract.IntegerType, manifest.NewParameter("hash", smartcontract.Hash256Type)) md = newMethodAndPrice(l.getTransactionVMState, 1<<15, callflag.ReadStates) @@ -148,6 +154,15 @@ func (l *Ledger) getTransactionFromBlock(ic *interop.Context, params []stackitem return TransactionToStackItem(block.Transactions[index]) } +// getTransactionSigners returns transaction signers to the SC. +func (l *Ledger) getTransactionSigners(ic *interop.Context, params []stackitem.Item) stackitem.Item { + tx, h, err := getTransactionAndHeight(ic.DAO, params[0]) + if err != nil || !isTraceableBlock(ic.Chain, h) { + return stackitem.Null{} + } + return SignersToStackItem(tx.Signers) +} + // getTransactionVMState returns VM state got after transaction invocation. func (l *Ledger) getTransactionVMState(ic *interop.Context, params []stackitem.Item) stackitem.Item { hash, err := getUint256FromItem(params[0]) @@ -242,3 +257,37 @@ func TransactionToStackItem(t *transaction.Transaction) stackitem.Item { stackitem.NewByteArray(t.Script), }) } + +// SignersToStackItem converts transaction.Signers to stackitem.Item. +func SignersToStackItem(signers []transaction.Signer) stackitem.Item { + res := make([]stackitem.Item, len(signers)) + bw := io.NewBufBinWriter() + for i, s := range signers { + s.EncodeBinary(bw.BinWriter) + if bw.Err != nil { + panic(fmt.Errorf("failed to serialize signer %d to stackitem: %w", i, bw.Err)) + } + contracts := make([]stackitem.Item, len(s.AllowedContracts)) + for j, c := range s.AllowedContracts { + contracts[j] = stackitem.NewByteArray(c.BytesBE()) + } + groups := make([]stackitem.Item, len(s.AllowedGroups)) + for j, g := range s.AllowedGroups { + groups[j] = stackitem.NewByteArray(g.Bytes()) + } + rules := make([]stackitem.Item, len(s.Rules)) + for j, r := range s.Rules { + rules[j] = r.ToStackItem() + } + res[i] = stackitem.NewArray([]stackitem.Item{ + stackitem.NewByteArray(bw.Bytes()), + stackitem.NewByteArray(s.Account.BytesBE()), + stackitem.NewBigInteger(big.NewInt(int64(s.Scopes))), + stackitem.NewArray(contracts), + stackitem.NewArray(groups), + stackitem.NewArray(rules), + }) + bw.Reset() + } + return stackitem.NewArray(res) +} diff --git a/pkg/core/native/native_test/ledger_test.go b/pkg/core/native/native_test/ledger_test.go index 9306f3008..b3fb555db 100644 --- a/pkg/core/native/native_test/ledger_test.go +++ b/pkg/core/native/native_test/ledger_test.go @@ -1,11 +1,16 @@ package native_test import ( + "fmt" "math/big" + "strings" "testing" + "github.com/nspcc-dev/neo-go/pkg/compiler" "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" + "github.com/nspcc-dev/neo-go/pkg/core/transaction" + "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/neotest" "github.com/nspcc-dev/neo-go/pkg/neotest/chain" "github.com/nspcc-dev/neo-go/pkg/util" @@ -172,3 +177,127 @@ func TestLedger_GetBlock(t *testing.T) { ledgerInvoker.Invoke(t, stackitem.Null{}, "getBlock", b.Hash()) }) } + +func TestLedger_GetTransactionSigners(t *testing.T) { + c := newLedgerClient(t) + e := c.Executor + ledgerInvoker := c.WithSigners(c.Committee) + + txHash := ledgerInvoker.Invoke(t, e.Chain.BlockHeight(), "currentIndex") + + t.Run("good", func(t *testing.T) { + s := &transaction.Signer{ + Account: c.CommitteeHash, + Scopes: transaction.Global, + } + bw := io.NewBufBinWriter() + s.EncodeBinary(bw.BinWriter) + require.NoError(t, bw.Err) + expected := stackitem.NewArray([]stackitem.Item{ + stackitem.NewArray([]stackitem.Item{ + stackitem.NewByteArray(bw.Bytes()), + stackitem.NewByteArray(s.Account.BytesBE()), + stackitem.NewBigInteger(big.NewInt(int64(s.Scopes))), + stackitem.NewArray([]stackitem.Item{}), + stackitem.NewArray([]stackitem.Item{}), + stackitem.NewArray([]stackitem.Item{}), + }), + }) + ledgerInvoker.Invoke(t, expected, "getTransactionSigners", txHash) + }) + t.Run("unknown transaction", func(t *testing.T) { + ledgerInvoker.Invoke(t, stackitem.Null{}, "getTransactionSigners", util.Uint256{1, 2, 3}) + }) + t.Run("not a hash", func(t *testing.T) { + ledgerInvoker.InvokeFail(t, "expected []byte of size 32", "getTransactionSigners", []byte{1, 2, 3}) + }) +} + +func TestLedger_GetTransactionSignersInteropAPI(t *testing.T) { + c := newLedgerClient(t) + e := c.Executor + ledgerInvoker := c.WithSigners(c.Committee) + + // Firstly, add transaction with CalledByEntry rule-based signer scope to the chain. + tx := e.NewUnsignedTx(t, ledgerInvoker.Hash, "currentIndex") + tx.Signers = []transaction.Signer{{ + Account: c.Committee.ScriptHash(), + Scopes: transaction.Rules, + Rules: []transaction.WitnessRule{ + { + Action: transaction.WitnessAllow, + Condition: transaction.ConditionCalledByEntry{}, + }, + }, + }} + neotest.AddNetworkFee(e.Chain, tx, c.Committee) + neotest.AddSystemFee(e.Chain, tx, -1) + require.NoError(t, c.Committee.SignTx(e.Chain.GetConfig().Magic, tx)) + c.AddNewBlock(t, tx) + c.CheckHalt(t, tx.Hash(), stackitem.Make(e.Chain.BlockHeight()-1)) + + var ( + hashStr string + accStr string + txHash = tx.Hash().BytesBE() + acc = c.Committee.ScriptHash().BytesBE() + ) + for i := 0; i < util.Uint256Size; i++ { + hashStr += fmt.Sprintf("%#x", txHash[i]) + if i != util.Uint256Size-1 { + hashStr += ", " + } + } + for i := 0; i < util.Uint160Size; i++ { + accStr += fmt.Sprintf("%#x", acc[i]) + if i != util.Uint160Size-1 { + accStr += ", " + } + } + + // After that ensure interop API allows to retrieve signer with CalledByEntry rule-based scope. + src := `package callledger + import ( + "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" + "github.com/nspcc-dev/neo-go/pkg/interop" + "github.com/nspcc-dev/neo-go/pkg/interop/util" + ) + func CallLedger(accessValue bool) int { + signers := ledger.GetTransactionSigners(interop.Hash256{` + hashStr + `}) + if len(signers) != 1 { + panic("bad length") + } + s0 := signers[0] + expectedAcc := interop.Hash160{` + accStr + `} + if !util.Equals(string(s0.Account), string(expectedAcc)) { + panic("bad account") + } + if s0.Scopes != ledger.Rules { + panic("bad signer scope") + } + if len(s0.Rules) != 1 { + panic("bad rules length") + } + r0 := s0.Rules[0] + if r0.Action != ledger.WitnessAllow { + panic("bad action") + } + c0 := r0.Condition + if c0.Type != ledger.WitnessCalledByEntry { + panic("bad condition type") + } + if accessValue { + // Panic should occur here, because there's only Type inside the CalledByEntry condition. + _ = c0.Value + } + return 1 + }` + ctr := neotest.CompileSource(t, c.Committee.ScriptHash(), strings.NewReader(src), &compiler.Options{ + Name: "calledger_contract", + }) + e.DeployContract(t, ctr, nil) + + ctrInvoker := e.NewInvoker(ctr.Hash, e.Committee) + ctrInvoker.Invoke(t, 1, "callLedger", false) // Firstly, don't access CalledByEnrty Condition value => the call should be successful. + ctrInvoker.InvokeFail(t, `(PICKITEM): unhandled exception: "The value 1 is out of range."`, "callLedger", true) // Then, access the value to ensure it will panic. +} diff --git a/pkg/core/transaction/witness_condition.go b/pkg/core/transaction/witness_condition.go index cb41b7746..fb8e6ce39 100644 --- a/pkg/core/transaction/witness_condition.go +++ b/pkg/core/transaction/witness_condition.go @@ -3,10 +3,12 @@ package transaction import ( "encoding/json" "errors" + "math/big" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) //go:generate stringer -type=WitnessConditionType -linecomment @@ -50,6 +52,8 @@ type WitnessCondition interface { // DecodeBinarySpecific decodes type-specific binary data from the given // reader (not including type data). DecodeBinarySpecific(*io.BinReader, int) + // ToStackItem converts WitnessCondition to stackitem.Item. + ToStackItem() stackitem.Item json.Marshaler } @@ -129,6 +133,12 @@ func (c *ConditionBoolean) MarshalJSON() ([]byte, error) { return json.Marshal(aux) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionBoolean) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), bool(*c)) +} + // Type implements WitnessCondition interface and returns condition type. func (c *ConditionNot) Type() WitnessConditionType { return WitnessNot @@ -166,6 +176,12 @@ func (c *ConditionNot) MarshalJSON() ([]byte, error) { return json.Marshal(aux) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionNot) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), c.Condition) +} + // Type implements WitnessCondition interface and returns condition type. func (c *ConditionAnd) Type() WitnessConditionType { return WitnessAnd @@ -242,6 +258,12 @@ func (c *ConditionAnd) MarshalJSON() ([]byte, error) { return arrayToJSON(c, []WitnessCondition(*c)) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionAnd) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), []WitnessCondition(*c)) +} + // Type implements WitnessCondition interface and returns condition type. func (c *ConditionOr) Type() WitnessConditionType { return WitnessOr @@ -282,6 +304,12 @@ func (c *ConditionOr) MarshalJSON() ([]byte, error) { return arrayToJSON(c, []WitnessCondition(*c)) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionOr) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), []WitnessCondition(*c)) +} + // Type implements WitnessCondition interface and returns condition type. func (c *ConditionScriptHash) Type() WitnessConditionType { return WitnessScriptHash @@ -314,6 +342,12 @@ func (c *ConditionScriptHash) MarshalJSON() ([]byte, error) { return json.Marshal(aux) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionScriptHash) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), util.Uint160(*c)) +} + // Type implements WitnessCondition interface and returns condition type. func (c *ConditionGroup) Type() WitnessConditionType { return WitnessGroup @@ -346,6 +380,12 @@ func (c *ConditionGroup) MarshalJSON() ([]byte, error) { return json.Marshal(aux) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionGroup) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), keys.PublicKey(*c)) +} + // Type implements WitnessCondition interface and returns condition type. func (c ConditionCalledByEntry) Type() WitnessConditionType { return WitnessCalledByEntry @@ -376,6 +416,12 @@ func (c ConditionCalledByEntry) MarshalJSON() ([]byte, error) { return json.Marshal(aux) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c ConditionCalledByEntry) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), nil) +} + // Type implements WitnessCondition interface and returns condition type. func (c *ConditionCalledByContract) Type() WitnessConditionType { return WitnessCalledByContract @@ -408,6 +454,12 @@ func (c *ConditionCalledByContract) MarshalJSON() ([]byte, error) { return json.Marshal(aux) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionCalledByContract) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), util.Uint160(*c)) +} + // Type implements WitnessCondition interface and returns condition type. func (c *ConditionCalledByGroup) Type() WitnessConditionType { return WitnessCalledByGroup @@ -440,6 +492,12 @@ func (c *ConditionCalledByGroup) MarshalJSON() ([]byte, error) { return json.Marshal(aux) } +// ToStackItem implements WitnessCondition interface allowing to convert +// to stackitem.Item. +func (c *ConditionCalledByGroup) ToStackItem() stackitem.Item { + return condToStackItem(c.Type(), keys.PublicKey(*c)) +} + // DecodeBinaryCondition decodes and returns condition from the given binary stream. func DecodeBinaryCondition(r *io.BinReader) WitnessCondition { return decodeBinaryCondition(r, MaxConditionNesting) @@ -573,3 +631,29 @@ func unmarshalConditionJSON(data []byte, maxDepth int) (WitnessCondition, error) } return res, nil } + +func condToStackItem(typ WitnessConditionType, c interface{}) stackitem.Item { + res := make([]stackitem.Item, 0, 2) + res = append(res, stackitem.NewBigInteger(big.NewInt(int64(typ)))) + switch typ { + case WitnessBoolean: + res = append(res, stackitem.NewBool(c.(bool))) + case WitnessNot: + res = append(res, c.(WitnessCondition).ToStackItem()) + case WitnessAnd, WitnessOr: + v := c.([]WitnessCondition) + operands := make([]stackitem.Item, len(v)) + for i, op := range v { + operands[i] = op.ToStackItem() + } + res = append(res, stackitem.NewArray(operands)) + case WitnessScriptHash, WitnessCalledByContract: + res = append(res, stackitem.NewByteArray(c.(util.Uint160).BytesBE())) + case WitnessGroup, WitnessCalledByGroup: + g := c.(keys.PublicKey) + res = append(res, stackitem.NewByteArray((&g).Bytes())) + case WitnessCalledByEntry: + // No additional item should be added. + } + return stackitem.NewArray(res) +} diff --git a/pkg/core/transaction/witness_condition_test.go b/pkg/core/transaction/witness_condition_test.go index 22afbd232..e8ac6d4fc 100644 --- a/pkg/core/transaction/witness_condition_test.go +++ b/pkg/core/transaction/witness_condition_test.go @@ -8,6 +8,8 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -30,10 +32,14 @@ func (c InvalidCondition) MarshalJSON() ([]byte, error) { } return json.Marshal(aux) } +func (c InvalidCondition) ToStackItem() stackitem.Item { + panic("invalid") +} type condCase struct { - condition WitnessCondition - success bool + condition WitnessCondition + success bool + expectedStackItem []stackitem.Item } func TestWitnessConditionSerDes(t *testing.T) { @@ -41,19 +47,25 @@ func TestWitnessConditionSerDes(t *testing.T) { pk, err := keys.NewPrivateKey() require.NoError(t, err) var cases = []condCase{ - {(*ConditionBoolean)(&someBool), true}, - {&ConditionNot{(*ConditionBoolean)(&someBool)}, true}, - {&ConditionAnd{(*ConditionBoolean)(&someBool), (*ConditionBoolean)(&someBool)}, true}, - {&ConditionOr{(*ConditionBoolean)(&someBool), (*ConditionBoolean)(&someBool)}, true}, - {&ConditionScriptHash{1, 2, 3}, true}, - {(*ConditionGroup)(pk.PublicKey()), true}, - {ConditionCalledByEntry{}, true}, - {&ConditionCalledByContract{1, 2, 3}, true}, - {(*ConditionCalledByGroup)(pk.PublicKey()), true}, - {InvalidCondition{}, false}, - {&ConditionAnd{}, false}, - {&ConditionOr{}, false}, - {&ConditionNot{&ConditionNot{&ConditionNot{(*ConditionBoolean)(&someBool)}}}, false}, + {(*ConditionBoolean)(&someBool), true, []stackitem.Item{stackitem.Make(WitnessBoolean), stackitem.Make(someBool)}}, + {&ConditionNot{(*ConditionBoolean)(&someBool)}, true, []stackitem.Item{stackitem.Make(WitnessNot), stackitem.NewArray([]stackitem.Item{stackitem.Make(WitnessBoolean), stackitem.Make(someBool)})}}, + {&ConditionAnd{(*ConditionBoolean)(&someBool), (*ConditionBoolean)(&someBool)}, true, []stackitem.Item{stackitem.Make(WitnessAnd), stackitem.Make([]stackitem.Item{ + stackitem.NewArray([]stackitem.Item{stackitem.Make(WitnessBoolean), stackitem.Make(someBool)}), + stackitem.NewArray([]stackitem.Item{stackitem.Make(WitnessBoolean), stackitem.Make(someBool)}), + })}}, + {&ConditionOr{(*ConditionBoolean)(&someBool), (*ConditionBoolean)(&someBool)}, true, []stackitem.Item{stackitem.Make(WitnessOr), stackitem.Make([]stackitem.Item{ + stackitem.NewArray([]stackitem.Item{stackitem.Make(WitnessBoolean), stackitem.Make(someBool)}), + stackitem.NewArray([]stackitem.Item{stackitem.Make(WitnessBoolean), stackitem.Make(someBool)}), + })}}, + {&ConditionScriptHash{1, 2, 3}, true, []stackitem.Item{stackitem.Make(WitnessScriptHash), stackitem.Make(util.Uint160{1, 2, 3}.BytesBE())}}, + {(*ConditionGroup)(pk.PublicKey()), true, []stackitem.Item{stackitem.Make(WitnessGroup), stackitem.Make(pk.PublicKey().Bytes())}}, + {ConditionCalledByEntry{}, true, []stackitem.Item{stackitem.Make(WitnessCalledByEntry)}}, + {&ConditionCalledByContract{1, 2, 3}, true, []stackitem.Item{stackitem.Make(WitnessCalledByContract), stackitem.Make(util.Uint160{1, 2, 3}.BytesBE())}}, + {(*ConditionCalledByGroup)(pk.PublicKey()), true, []stackitem.Item{stackitem.Make(WitnessCalledByGroup), stackitem.Make(pk.PublicKey().Bytes())}}, + {InvalidCondition{}, false, nil}, + {&ConditionAnd{}, false, nil}, + {&ConditionOr{}, false, nil}, + {&ConditionNot{&ConditionNot{&ConditionNot{(*ConditionBoolean)(&someBool)}}}, false, nil}, } var maxSubCondAnd = &ConditionAnd{} var maxSubCondOr = &ConditionAnd{} @@ -61,8 +73,8 @@ func TestWitnessConditionSerDes(t *testing.T) { *maxSubCondAnd = append(*maxSubCondAnd, (*ConditionBoolean)(&someBool)) *maxSubCondOr = append(*maxSubCondOr, (*ConditionBoolean)(&someBool)) } - cases = append(cases, condCase{maxSubCondAnd, false}) - cases = append(cases, condCase{maxSubCondOr, false}) + cases = append(cases, condCase{maxSubCondAnd, false, nil}) + cases = append(cases, condCase{maxSubCondOr, false, nil}) t.Run("binary", func(t *testing.T) { for i, c := range cases { w := io.NewBufBinWriter() @@ -94,6 +106,15 @@ func TestWitnessConditionSerDes(t *testing.T) { require.Equal(t, c.condition, res) } }) + t.Run("stackitem", func(t *testing.T) { + for i, c := range cases[1:] { + if c.expectedStackItem != nil { + expected := stackitem.NewArray(c.expectedStackItem) + actual := c.condition.ToStackItem() + assert.Equal(t, expected, actual, i) + } + } + }) } func TestWitnessConditionZeroDeser(t *testing.T) { diff --git a/pkg/core/transaction/witness_rule.go b/pkg/core/transaction/witness_rule.go index 75ab4abcd..15edeb699 100644 --- a/pkg/core/transaction/witness_rule.go +++ b/pkg/core/transaction/witness_rule.go @@ -3,8 +3,10 @@ package transaction import ( "encoding/json" "errors" + "math/big" "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) //go:generate stringer -type=WitnessAction -linecomment @@ -84,3 +86,11 @@ func (w *WitnessRule) UnmarshalJSON(data []byte) error { w.Condition = cond return nil } + +// ToStackItem implements Convertible interface. +func (w *WitnessRule) ToStackItem() stackitem.Item { + return stackitem.NewArray([]stackitem.Item{ + stackitem.NewBigInteger(big.NewInt(int64(w.Action))), + w.Condition.ToStackItem(), + }) +} diff --git a/pkg/core/transaction/witness_rule_test.go b/pkg/core/transaction/witness_rule_test.go index 70bf9c38d..bde78568a 100644 --- a/pkg/core/transaction/witness_rule_test.go +++ b/pkg/core/transaction/witness_rule_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/nspcc-dev/neo-go/internal/testserdes" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/stretchr/testify/require" ) @@ -54,3 +55,21 @@ func TestWitnessRuleBadJSON(t *testing.T) { require.Errorf(t, err, "case %d, json %s", i, cases[i]) } } + +func TestWitnessRule_ToStackItem(t *testing.T) { + var b bool + for _, act := range []WitnessAction{WitnessDeny, WitnessAllow} { + expected := stackitem.NewArray([]stackitem.Item{ + stackitem.Make(int64(act)), + stackitem.Make([]stackitem.Item{ + stackitem.Make(WitnessBoolean), + stackitem.Make(b), + }), + }) + actual := (&WitnessRule{ + Action: act, + Condition: (*ConditionBoolean)(&b), + }).ToStackItem() + require.Equal(t, expected, actual, act) + } +} diff --git a/pkg/interop/native/ledger/ledger.go b/pkg/interop/native/ledger/ledger.go index 4b3c0ef2e..d0e3956f1 100644 --- a/pkg/interop/native/ledger/ledger.go +++ b/pkg/interop/native/ledger/ledger.go @@ -59,6 +59,12 @@ func GetTransactionFromBlock(indexOrHash interface{}, txIndex int) *Transaction indexOrHash, txIndex).(*Transaction) } +// GetTransactionSigners represents `getTransactionSigners` method of Ledger native contract. +func GetTransactionSigners(hash interop.Hash256) []TransactionSigner { + return neogointernal.CallWithToken(Hash, "getTransactionSigners", int(contract.ReadStates), + hash).([]TransactionSigner) +} + // GetTransactionVMState represents `getTransactionVMState` method of Ledger native contract. func GetTransactionVMState(hash interop.Hash256) VMState { return neogointernal.CallWithToken(Hash, "getTransactionVMState", int(contract.ReadStates), hash).(VMState) diff --git a/pkg/interop/native/ledger/transaction_signer.go b/pkg/interop/native/ledger/transaction_signer.go new file mode 100644 index 000000000..b27ab735a --- /dev/null +++ b/pkg/interop/native/ledger/transaction_signer.go @@ -0,0 +1,116 @@ +package ledger + +import "github.com/nspcc-dev/neo-go/pkg/interop" + +// TransactionSigner represent the signer of a NEO transaction. It's similar to +// Signer class in Neo .net framework. +type TransactionSigner struct { + // Bytes is a binary serialized representation of the given signer. + Bytes []byte + // Account represents the account (160 bit BE value in a 20 byte slice) of + // the given signer. + Account interop.Hash160 + // Scopes represents a set of witness flags for the given signer. + Scopes SignerScope + // Contracts represents the set of contract hashes (160 bit BE value in a 20 + // byte slice) allowed to be called by the signer. It is only non-empty if + // CustomContracts scope flag is set. + AllowedContracts []interop.Hash160 + // AllowedGroups represents the set of contract groups (ecdsa public key + // bytes in a 33 byte slice) allowed to be called by the signer. It is only + // non-empty if CustomGroups scope flag is set. + AllowedGroups []interop.PublicKey + // Rules represents a rule-based witness scope of the given signer. It is + // only non-empty if Rules scope flag is set. + Rules []WitnessRule +} + +// SignerScope represents a signer's witness scope. +type SignerScope byte + +// Various witness scopes. +const ( + // None specifies that no contract was witnessed. Only signs the transaction + // and pays GAS fee if a sender. + None SignerScope = 0 + // CalledByEntry means that the witness is valid only when the witness + // checking contract is called from the entry script. + CalledByEntry SignerScope = 0x01 + // CustomContracts define custom hash for contract-specific witness. + CustomContracts SignerScope = 0x10 + // CustomGroups define custom public key for group members. + CustomGroups SignerScope = 0x20 + // Rules is a set of conditions with boolean operators. + Rules SignerScope = 0x40 + // Global allows this witness in all contexts. This cannot be combined with + // other flags. + Global SignerScope = 0x80 +) + +// WitnessRule represents a single rule for Rules witness scope. +type WitnessRule struct { + // Action denotes whether the witness condition should be accepted or denied. + Action WitnessAction + // Condition holds a set of nested witness rules. Max nested depth is 2. + Condition WitnessCondition +} + +// WitnessAction represents an action to perform in WitnessRule if +// witness condition matches. +type WitnessAction byte + +// Various rule-based witness actions. +const ( + // WitnessDeny rejects current witness if condition is met. + WitnessDeny WitnessAction = 0 + // WitnessAllow approves current witness if condition is met. + WitnessAllow WitnessAction = 1 +) + +// WitnessCondition represents a single witness condition for a rule-based +// witness. Its type can always be safely accessed, but trying to access its +// value causes runtime exception for those types that don't have value +// (currently, it's only CalledByEntry witness condition). +type WitnessCondition struct { + Type WitnessConditionType + // Depends on the witness condition Type, its value can be asserted to the + // certain structure according to the following rule: + // WitnessBoolean -> bool + // WitnessNot -> []WitnessCondition with one element + // WitnessAnd -> []WitnessCondition + // WitnessOr -> []WitnessCondition + // WitnessScriptHash -> interop.Hash160 + // WitnessGroup -> interop.PublicKey + // WitnessCalledByContract -> interop.Hash160 + // WitnessCalledByGroup -> interop.PublicKey + // WitnessCalledByEntry -> doesn't have value, thus, an attempt to access the Value leads to runtime exception. + Value interface{} +} + +// WitnessConditionType represents the type of rule-based witness condition. +type WitnessConditionType byte + +// Various witness condition types +const ( + // WitnessBoolean is a generic boolean condition. + WitnessBoolean WitnessConditionType = 0x00 + // WitnessNot reverses another condition. + WitnessNot WitnessConditionType = 0x01 + // WitnessAnd means that all conditions must be met. + WitnessAnd WitnessConditionType = 0x02 + // WitnessOr means that any of conditions must be met. + WitnessOr WitnessConditionType = 0x03 + // WitnessScriptHash matches executing contract's script hash. + WitnessScriptHash WitnessConditionType = 0x18 + // WitnessGroup matches executing contract's group key. + WitnessGroup WitnessConditionType = 0x19 + // WitnessCalledByEntry matches when current script is an entry script or is + // called by an entry script. + WitnessCalledByEntry WitnessConditionType = 0x20 + // WitnessCalledByContract matches when current script is called by the + // specified contract. + WitnessCalledByContract WitnessConditionType = 0x28 + // WitnessCalledByGroup matches when current script is called by contract + // belonging to the specified group. + WitnessCalledByGroup WitnessConditionType = 0x29 +) diff --git a/pkg/neotest/basic.go b/pkg/neotest/basic.go index 7904914e2..9ddfd72cf 100644 --- a/pkg/neotest/basic.go +++ b/pkg/neotest/basic.go @@ -107,8 +107,8 @@ func (e *Executor) SignTx(t testing.TB, tx *transaction.Transaction, sysFee int6 Scopes: transaction.Global, }) } - addNetworkFee(e.Chain, tx, signers...) - addSystemFee(e.Chain, tx, sysFee) + AddNetworkFee(e.Chain, tx, signers...) + AddSystemFee(e.Chain, tx, sysFee) for _, acc := range signers { require.NoError(t, acc.SignTx(e.Chain.GetConfig().Magic, tx)) @@ -276,12 +276,14 @@ func NewDeployTxBy(t testing.TB, bc blockchainer.Blockchainer, signer Signer, c Account: signer.ScriptHash(), Scopes: transaction.Global, }} - addNetworkFee(bc, tx, signer) + AddNetworkFee(bc, tx, signer) require.NoError(t, signer.SignTx(netmode.UnitTestNet, tx)) return tx } -func addSystemFee(bc blockchainer.Blockchainer, tx *transaction.Transaction, sysFee int64) { +// AddSystemFee adds system fee to the transaction. If negative value specified, +// then system fee is defined by test invocation. +func AddSystemFee(bc blockchainer.Blockchainer, tx *transaction.Transaction, sysFee int64) { if sysFee >= 0 { tx.SystemFee = sysFee return @@ -290,7 +292,8 @@ func addSystemFee(bc blockchainer.Blockchainer, tx *transaction.Transaction, sys tx.SystemFee = v.GasConsumed() } -func addNetworkFee(bc blockchainer.Blockchainer, tx *transaction.Transaction, signers ...Signer) { +// AddNetworkFee adds network fee to the transaction. +func AddNetworkFee(bc blockchainer.Blockchainer, tx *transaction.Transaction, signers ...Signer) { baseFee := bc.GetBaseExecFee() size := io.GetVarSize(tx) for _, sgr := range signers {