Merge pull request #2702 from nspcc-dev/management-id-hash

Store ID->hash map in the ContractManagement
This commit is contained in:
Roman Khimov 2022-12-02 23:48:44 +07:00 committed by GitHub
commit a654396150
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 509 additions and 130 deletions

View file

@ -27,6 +27,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig" "github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -856,8 +857,7 @@ func handleLoadDeployed(c *cli.Context) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to parse contract hash, address or ID: %w", err) return fmt.Errorf("failed to parse contract hash, address or ID: %w", err)
} }
bc := getChainFromContext(c.App) h, err = native.GetContractScriptHash(ic.DAO, int32(i))
h, err = bc.GetContractScriptHash(int32(i)) // @fixme: can be improved after #2702 to retrieve historic state of destroyed contract by ID.
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve contract hash by ID: %w", err) return fmt.Errorf("failed to retrieve contract hash by ID: %w", err)
} }

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -4,7 +4,7 @@ go 1.17
require ( require (
github.com/nspcc-dev/neo-go v0.99.5-0.20221108145959-8746d9877eb5 github.com/nspcc-dev/neo-go v0.99.5-0.20221108145959-8746d9877eb5
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
) )

View file

@ -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/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 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 v0.99.5-0.20221108145959-8746d9877eb5/go.mod h1:aWrWJZBYO+9kYC4+qJXvEjySW1WIyPnrHpmdrzd5mJY=
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
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 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ=
github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= 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= github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 h1:rpMCoRa7expLc9gMiOP724gz6YSykZzmMALR/CmiwnU=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

2
go.mod
View file

@ -12,7 +12,7 @@ require (
github.com/mr-tron/base58 v1.2.0 github.com/mr-tron/base58 v1.2.0
github.com/nspcc-dev/dbft v0.0.0-20221020093431-31c1bbdc74f2 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/go-ordered-json v0.0.0-20220111165707-25110be27d22
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659
github.com/nspcc-dev/rfc6979 v0.2.0 github.com/nspcc-dev/rfc6979 v0.2.0
github.com/pierrec/lz4 v2.6.1+incompatible github.com/pierrec/lz4 v2.6.1+incompatible

4
go.sum
View file

@ -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/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.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.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/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.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 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
go 1.17 go 1.17
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb

View file

@ -1,2 +1,2 @@
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-20221202075445-cb5c18dc73eb h1:GFxfkpXEYAbMIr69JpKOsQWeLOaGrd49HNAor8uDW+A=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221125121149-de2de986a7ff/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=

View file

@ -205,6 +205,8 @@ func TestNativeHelpersCompile(t *testing.T) {
{"deployWithData", []string{"nil", "nil", "123"}}, {"deployWithData", []string{"nil", "nil", "123"}},
{"destroy", nil}, {"destroy", nil},
{"getContract", []string{u160}}, {"getContract", []string{u160}},
{"getContractById", []string{"1"}},
{"getContractHashes", nil},
{"getMinimumDeploymentFee", nil}, {"getMinimumDeploymentFee", nil},
{"hasMethod", []string{u160, `"method"`, "0"}}, {"hasMethod", []string{u160, `"method"`, "0"}},
{"setMinimumDeploymentFee", []string{"42"}}, {"setMinimumDeploymentFee", []string{"42"}},
@ -300,6 +302,7 @@ func addNativeTestCase(t *testing.T, srcBuilder *bytes.Buffer, ctr interop.Contr
methodUpper := strings.ToUpper(method[:1]) + method[1:] // ASCII only methodUpper := strings.ToUpper(method[:1]) + method[1:] // ASCII only
methodUpper = strings.ReplaceAll(methodUpper, "Gas", "GAS") methodUpper = strings.ReplaceAll(methodUpper, "Gas", "GAS")
methodUpper = strings.ReplaceAll(methodUpper, "Json", "JSON") methodUpper = strings.ReplaceAll(methodUpper, "Json", "JSON")
methodUpper = strings.ReplaceAll(methodUpper, "Id", "ID")
srcBuilder.WriteString(name) srcBuilder.WriteString(name)
srcBuilder.WriteRune('.') srcBuilder.WriteRune('.')
srcBuilder.WriteString(methodUpper) srcBuilder.WriteString(methodUpper)

View file

@ -45,7 +45,7 @@ import (
// Tuning parameters. // Tuning parameters.
const ( const (
version = "0.2.6" version = "0.2.7"
defaultInitialGAS = 52000000_00000000 defaultInitialGAS = 52000000_00000000
defaultGCPeriod = 10000 defaultGCPeriod = 10000
@ -717,21 +717,9 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
p = time.Now() p = time.Now()
fallthrough fallthrough
case staleBlocksRemoved: case staleBlocksRemoved:
// Completely remove contract IDs to update them later. bc.log.Info("trying to reset contract storage items")
bc.log.Info("trying to reset contract storage items and IDs")
pStorageStart := p pStorageStart := p
cache.Store.Seek(storage.SeekRange{Prefix: []byte{byte(storage.STContractID)}}, func(k, _ []byte) bool {
cache.Store.Delete(k)
return true
})
keys, err = cache.Persist()
if err != nil {
return fmt.Errorf("failed to persist removed contract IDs: %w", err)
}
bc.log.Info("removed contract IDs are persisted", zap.Duration("took", time.Since(p)), zap.Int("keys", keys))
p = time.Now()
// Reset contracts storage and store new contract IDs.
var mode = mpt.ModeAll var mode = mpt.ModeAll
if bc.config.RemoveUntraceableBlocks { if bc.config.RemoveUntraceableBlocks {
mode |= mpt.ModeGCFlag mode |= mpt.ModeGCFlag
@ -739,19 +727,12 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
trieStore := mpt.NewTrieStore(sr.Root, mode, cache.Store) trieStore := mpt.NewTrieStore(sr.Root, mode, cache.Store)
oldStoragePrefix := v.StoragePrefix oldStoragePrefix := v.StoragePrefix
newStoragePrefix := statesync.TemporaryPrefix(oldStoragePrefix) newStoragePrefix := statesync.TemporaryPrefix(oldStoragePrefix)
mgmtCSPrefixLen := 1 + 4 + 1 // STStorage + Management ID + contract state prefix
mgmtContractPrefix := make([]byte, mgmtCSPrefixLen-1)
id := int32(native.ManagementContractID)
binary.BigEndian.PutUint32(mgmtContractPrefix, uint32(id))
mgmtContractPrefix[4] = native.PrefixContract
cs := new(state.Contract)
const persistBatchSize = 200000 const persistBatchSize = 200000
var ( var (
seekErr error seekErr error
cnt int cnt int
storageItmsCnt int storageItmsCnt int
contractIDsCnt int
batchCnt int batchCnt int
) )
trieStore.Seek(storage.SeekRange{Prefix: []byte{byte(oldStoragePrefix)}}, func(k, v []byte) bool { trieStore.Seek(storage.SeekRange{Prefix: []byte{byte(oldStoragePrefix)}}, func(k, v []byte) bool {
@ -775,22 +756,6 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
cnt++ cnt++
storageItmsCnt++ storageItmsCnt++
// @fixme: remove this part after #2702.
if bytes.HasPrefix(k[1:], mgmtContractPrefix) {
var hash util.Uint160
copy(hash[:], k[mgmtCSPrefixLen:])
err = stackitem.DeserializeConvertible(v, cs)
if err != nil {
bc.log.Warn("failed to deserialize contract; ID for this contract won't be stored in the DB",
zap.String("hash", hash.StringLE()),
zap.Error(err))
} else {
cache.PutContractID(cs.ID, hash)
cnt++
contractIDsCnt++
}
}
return true return true
}) })
if seekErr != nil { if seekErr != nil {
@ -806,8 +771,7 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
batchCnt++ batchCnt++
bc.log.Info("last batch of contract storage items and IDs is persisted", zap.Int("batch", batchCnt), zap.Duration("took", time.Since(p)), zap.Int("keys", keys)) bc.log.Info("last batch of contract storage items and IDs is persisted", zap.Int("batch", batchCnt), zap.Duration("took", time.Since(p)), zap.Int("keys", keys))
bc.log.Info("contract storage items and IDs are reset", zap.Duration("took", time.Since(pStorageStart)), bc.log.Info("contract storage items and IDs are reset", zap.Duration("took", time.Since(pStorageStart)),
zap.Int("keys", storageItmsCnt), zap.Int("keys", storageItmsCnt))
zap.Int("ids", contractIDsCnt))
p = time.Now() p = time.Now()
fallthrough fallthrough
case newStorageItemsAdded: case newStorageItemsAdded:
@ -1774,7 +1738,7 @@ func (bc *Blockchain) processTokenTransfer(cache *dao.Simple, transCache map[uti
if nativeContract != nil { if nativeContract != nil {
id = nativeContract.Metadata().ID id = nativeContract.Metadata().ID
} else { } else {
assetContract, err := bc.contracts.Management.GetContract(cache, sc) assetContract, err := native.GetContract(cache, sc)
if err != nil { if err != nil {
return return
} }
@ -2112,7 +2076,7 @@ func (bc *Blockchain) BlockHeight() uint32 {
// GetContractState returns contract by its script hash. // GetContractState returns contract by its script hash.
func (bc *Blockchain) GetContractState(hash util.Uint160) *state.Contract { func (bc *Blockchain) GetContractState(hash util.Uint160) *state.Contract {
contract, err := bc.contracts.Management.GetContract(bc.dao, hash) contract, err := native.GetContract(bc.dao, hash)
if contract == nil && !errors.Is(err, storage.ErrKeyNotFound) { if contract == nil && !errors.Is(err, storage.ErrKeyNotFound) {
bc.log.Warn("failed to get contract state", zap.Error(err)) bc.log.Warn("failed to get contract state", zap.Error(err))
} }
@ -2121,7 +2085,7 @@ func (bc *Blockchain) GetContractState(hash util.Uint160) *state.Contract {
// GetContractScriptHash returns contract script hash by its ID. // GetContractScriptHash returns contract script hash by its ID.
func (bc *Blockchain) GetContractScriptHash(id int32) (util.Uint160, error) { func (bc *Blockchain) GetContractScriptHash(id int32) (util.Uint160, error) {
return bc.dao.GetContractScriptHash(id) return native.GetContractScriptHash(bc.dao, id)
} }
// GetNativeContractScriptHash returns native contract script hash by its name. // GetNativeContractScriptHash returns native contract script hash by its name.
@ -2823,7 +2787,7 @@ func (bc *Blockchain) newInteropContext(trigger trigger.Type, d *dao.Simple, blo
// changes that were not yet persisted to Blockchain's dao. // changes that were not yet persisted to Blockchain's dao.
baseStorageFee = bc.contracts.Policy.GetStoragePriceInternal(d) baseStorageFee = bc.contracts.Policy.GetStoragePriceInternal(d)
} }
ic := interop.NewContext(trigger, bc, d, baseExecFee, baseStorageFee, bc.contracts.Management.GetContract, bc.contracts.Contracts, contract.LoadToken, block, tx, bc.log) ic := interop.NewContext(trigger, bc, d, baseExecFee, baseStorageFee, native.GetContract, bc.contracts.Contracts, contract.LoadToken, block, tx, bc.log)
ic.Functions = systemInterops ic.Functions = systemInterops
switch { switch {
case tx != nil: case tx != nil:

View file

@ -135,32 +135,6 @@ func (dao *Simple) putWithBuffer(entity io.Serializable, key []byte, buf *io.Buf
return nil return nil
} }
func (dao *Simple) makeContractIDKey(id int32) []byte {
key := dao.getKeyBuf(5)
key[0] = byte(storage.STContractID)
binary.BigEndian.PutUint32(key[1:], uint32(id))
return key
}
// DeleteContractID deletes contract's id to hash mapping.
func (dao *Simple) DeleteContractID(id int32) {
dao.Store.Delete(dao.makeContractIDKey(id))
}
// PutContractID adds a mapping from a contract's ID to its hash.
func (dao *Simple) PutContractID(id int32, hash util.Uint160) {
dao.Store.Put(dao.makeContractIDKey(id), hash.BytesBE())
}
// GetContractScriptHash retrieves the contract's hash given its ID.
func (dao *Simple) GetContractScriptHash(id int32) (util.Uint160, error) {
var data = new(util.Uint160)
if err := dao.GetAndDecode(data, dao.makeContractIDKey(id)); err != nil {
return *data, err
}
return *data, nil
}
// -- start NEP-17 transfer info. // -- start NEP-17 transfer info.
func (dao *Simple) makeTTIKey(acc util.Uint160) []byte { func (dao *Simple) makeTTIKey(acc util.Uint160) []byte {

View file

@ -1,6 +1,8 @@
package native package native
import ( import (
"context"
"encoding/binary"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -11,6 +13,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
istorage "github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
@ -45,6 +48,7 @@ const (
// PrefixContract is a prefix used to store contract states inside Management native contract. // PrefixContract is a prefix used to store contract states inside Management native contract.
PrefixContract = 8 PrefixContract = 8
prefixContractHash = 12
defaultMinimumDeploymentFee = 10_00000000 defaultMinimumDeploymentFee = 10_00000000
contractDeployNotificationName = "Deploy" contractDeployNotificationName = "Deploy"
@ -149,6 +153,15 @@ func newManagement() *Management {
md = newMethodAndPrice(m.hasMethod, 1<<15, callflag.ReadStates) md = newMethodAndPrice(m.hasMethod, 1<<15, callflag.ReadStates)
m.AddMethod(md, desc) m.AddMethod(md, desc)
desc = newDescriptor("getContractById", smartcontract.ArrayType,
manifest.NewParameter("id", smartcontract.IntegerType))
md = newMethodAndPrice(m.getContractByID, 1<<15, callflag.ReadStates)
m.AddMethod(md, desc)
desc = newDescriptor("getContractHashes", smartcontract.InteropInterfaceType)
md = newMethodAndPrice(m.getContractHashes, 1<<15, callflag.ReadStates)
m.AddMethod(md, desc)
hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type) hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type)
m.AddEvent(contractDeployNotificationName, hashParam) m.AddEvent(contractDeployNotificationName, hashParam)
m.AddEvent(contractUpdateNotificationName, hashParam) m.AddEvent(contractUpdateNotificationName, hashParam)
@ -172,7 +185,28 @@ func toHash160(si stackitem.Item) util.Uint160 {
// VM protections, so it's OK for it to panic instead of returning errors. // VM protections, so it's OK for it to panic instead of returning errors.
func (m *Management) getContract(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (m *Management) getContract(ic *interop.Context, args []stackitem.Item) stackitem.Item {
hash := toHash160(args[0]) hash := toHash160(args[0])
ctr, err := m.GetContract(ic.DAO, hash) ctr, err := GetContract(ic.DAO, hash)
if err != nil {
if errors.Is(err, storage.ErrKeyNotFound) {
return stackitem.Null{}
}
panic(err)
}
return contractToStack(ctr)
}
// getContractByID is an implementation of public getContractById method, it's run under
// VM protections, so it's OK for it to panic instead of returning errors.
func (m *Management) getContractByID(ic *interop.Context, args []stackitem.Item) stackitem.Item {
idBig, err := args[0].TryInteger()
if err != nil {
panic(err)
}
id := idBig.Int64()
if !idBig.IsInt64() || id < math.MinInt32 || id > math.MaxInt32 {
panic("id is not a correct int32")
}
ctr, err := GetContractByID(ic.DAO, int32(id))
if err != nil { if err != nil {
if errors.Is(err, storage.ErrKeyNotFound) { if errors.Is(err, storage.ErrKeyNotFound) {
return stackitem.Null{} return stackitem.Null{}
@ -183,8 +217,8 @@ func (m *Management) getContract(ic *interop.Context, args []stackitem.Item) sta
} }
// GetContract returns a contract with the given hash from the given DAO. // GetContract returns a contract with the given hash from the given DAO.
func (m *Management) GetContract(d *dao.Simple, hash util.Uint160) (*state.Contract, error) { func GetContract(d *dao.Simple, hash util.Uint160) (*state.Contract, error) {
cache := d.GetROCache(m.ID).(*ManagementCache) cache := d.GetROCache(ManagementContractID).(*ManagementCache)
cs, ok := cache.contracts[hash] cs, ok := cache.contracts[hash]
if !ok { if !ok {
return nil, storage.ErrKeyNotFound return nil, storage.ErrKeyNotFound
@ -192,6 +226,26 @@ func (m *Management) GetContract(d *dao.Simple, hash util.Uint160) (*state.Contr
return cs, nil return cs, nil
} }
// GetContractByID returns a contract with the given ID from the given DAO.
func GetContractByID(d *dao.Simple, id int32) (*state.Contract, error) {
hash, err := GetContractScriptHash(d, id)
if err != nil {
return nil, err
}
return GetContract(d, hash)
}
// GetContractScriptHash returns a contract hash associated with the given ID from the given DAO.
func GetContractScriptHash(d *dao.Simple, id int32) (util.Uint160, error) {
key := make([]byte, 5)
key = putHashKey(key, id)
si := d.GetStorageItem(ManagementContractID, key)
if si == nil {
return util.Uint160{}, storage.ErrKeyNotFound
}
return util.Uint160DecodeBytesBE(si)
}
func getLimitedSlice(arg stackitem.Item, max int) ([]byte, error) { func getLimitedSlice(arg stackitem.Item, max int) ([]byte, error) {
_, isNull := arg.(stackitem.Null) _, isNull := arg.(stackitem.Null)
if isNull { if isNull {
@ -211,6 +265,29 @@ func getLimitedSlice(arg stackitem.Item, max int) ([]byte, error) {
return b, nil return b, nil
} }
func (m *Management) getContractHashes(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
ctx, cancel := context.WithCancel(context.Background())
prefix := []byte{prefixContractHash}
seekres := ic.DAO.SeekAsync(ctx, ManagementContractID, storage.SeekRange{Prefix: prefix})
filteredRes := make(chan storage.KeyValue)
go func() {
for kv := range seekres {
if len(kv.Key) == 4 && binary.BigEndian.Uint32(kv.Key) < math.MaxInt32 {
filteredRes <- kv
}
}
close(filteredRes)
}()
opts := istorage.FindRemovePrefix
item := istorage.NewIterator(filteredRes, prefix, int64(opts))
ic.RegisterCancelFunc(func() {
cancel()
for range seekres {
}
})
return stackitem.NewInterop(item)
}
// getNefAndManifestFromItems converts input arguments into NEF and manifest // getNefAndManifestFromItems converts input arguments into NEF and manifest
// adding an appropriate deployment GAS price and sanitizing inputs. // adding an appropriate deployment GAS price and sanitizing inputs.
func (m *Management) getNefAndManifestFromItems(ic *interop.Context, args []stackitem.Item, isDeploy bool) (*nef.File, *manifest.Manifest, error) { func (m *Management) getNefAndManifestFromItems(ic *interop.Context, args []stackitem.Item, isDeploy bool) (*nef.File, *manifest.Manifest, error) {
@ -303,7 +380,7 @@ func (m *Management) Deploy(d *dao.Simple, sender util.Uint160, neff *nef.File,
if m.Policy.IsBlocked(d, h) { if m.Policy.IsBlocked(d, h) {
return nil, fmt.Errorf("the contract %s has been blocked", h.StringLE()) return nil, fmt.Errorf("the contract %s has been blocked", h.StringLE())
} }
_, err := m.GetContract(d, h) _, err := GetContract(d, h)
if err == nil { if err == nil {
return nil, errors.New("contract already exists") return nil, errors.New("contract already exists")
} }
@ -362,7 +439,7 @@ func (m *Management) updateWithData(ic *interop.Context, args []stackitem.Item)
func (m *Management) Update(d *dao.Simple, hash util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) { func (m *Management) Update(d *dao.Simple, hash util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) {
var contract state.Contract var contract state.Contract
oldcontract, err := m.GetContract(d, hash) oldcontract, err := GetContract(d, hash)
if err != nil { if err != nil {
return nil, errors.New("contract doesn't exist") return nil, errors.New("contract doesn't exist")
} }
@ -412,13 +489,14 @@ func (m *Management) destroy(ic *interop.Context, sis []stackitem.Item) stackite
// Destroy drops the given contract from DAO along with its storage. It doesn't emit notification. // Destroy drops the given contract from DAO along with its storage. It doesn't emit notification.
func (m *Management) Destroy(d *dao.Simple, hash util.Uint160) error { func (m *Management) Destroy(d *dao.Simple, hash util.Uint160) error {
contract, err := m.GetContract(d, hash) contract, err := GetContract(d, hash)
if err != nil { if err != nil {
return err return err
} }
key := MakeContractKey(hash) key := MakeContractKey(hash)
d.DeleteStorageItem(m.ID, key) d.DeleteStorageItem(m.ID, key)
d.DeleteContractID(contract.ID) key = putHashKey(key, contract.ID)
d.DeleteStorageItem(ManagementContractID, key)
d.Seek(contract.ID, storage.SeekRange{}, func(k, _ []byte) bool { d.Seek(contract.ID, storage.SeekRange{}, func(k, _ []byte) bool {
d.DeleteStorageItem(contract.ID, k) d.DeleteStorageItem(contract.ID, k)
@ -476,7 +554,7 @@ func (m *Management) hasMethod(ic *interop.Context, args []stackitem.Item) stack
panic(err) panic(err)
} }
pcount := int(toInt64((args[2]))) pcount := int(toInt64((args[2])))
cs, err := m.GetContract(ic.DAO, cHash) cs, err := GetContract(ic.DAO, cHash)
if err != nil { if err != nil {
return stackitem.NewBool(false) return stackitem.NewBool(false)
} }
@ -610,10 +688,17 @@ func putContractState(d *dao.Simple, cs *state.Contract, updateCache bool) error
if cs.UpdateCounter != 0 { // Update. if cs.UpdateCounter != 0 { // Update.
return nil return nil
} }
d.PutContractID(cs.ID, cs.Hash) key = putHashKey(key, cs.ID)
d.PutStorageItem(ManagementContractID, key, cs.Hash.BytesBE())
return nil return nil
} }
func putHashKey(buf []byte, id int32) []byte {
buf[0] = prefixContractHash
binary.BigEndian.PutUint32(buf[1:], uint32(id))
return buf[:5]
}
func (m *Management) getNextContractID(d *dao.Simple) (int32, error) { func (m *Management) getNextContractID(d *dao.Simple) (int32, error) {
si := d.GetStorageItem(m.ID, keyNextAvailableID) si := d.GetStorageItem(m.ID, keyNextAvailableID)
if si == nil { if si == nil {

View file

@ -57,7 +57,11 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) {
require.Equal(t, ne, &contract2.NEF) require.Equal(t, ne, &contract2.NEF)
require.Equal(t, *manif, contract2.Manifest) require.Equal(t, *manif, contract2.Manifest)
refContract, err := mgmt.GetContract(d, h) refContract, err := GetContract(d, h)
require.NoError(t, err)
require.Equal(t, contract, refContract)
refContract, err = GetContractByID(d, contract.ID)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, contract, refContract) require.Equal(t, contract, refContract)
@ -68,7 +72,9 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) {
err = mgmt.Destroy(d, h) err = mgmt.Destroy(d, h)
require.NoError(t, err) require.NoError(t, err)
_, err = mgmt.GetContract(d, h) _, err = GetContract(d, h)
require.Error(t, err)
_, err = GetContractByID(d, contract.ID)
require.Error(t, err) require.Error(t, err)
} }
@ -140,11 +146,11 @@ func TestManagement_GetNEP17Contracts(t *testing.T) {
// No changes expected in lower store. // No changes expected in lower store.
require.Equal(t, []util.Uint160{c1.Hash}, mgmt.GetNEP17Contracts(d)) require.Equal(t, []util.Uint160{c1.Hash}, mgmt.GetNEP17Contracts(d))
c1Lower, err := mgmt.GetContract(d, c1.Hash) c1Lower, err := GetContract(d, c1.Hash)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c1Lower.Manifest.ABI.Methods)) require.Equal(t, 1, len(c1Lower.Manifest.ABI.Methods))
require.Equal(t, []util.Uint160{c1Updated.Hash}, mgmt.GetNEP17Contracts(private)) require.Equal(t, []util.Uint160{c1Updated.Hash}, mgmt.GetNEP17Contracts(private))
c1Upper, err := mgmt.GetContract(private, c1Updated.Hash) c1Upper, err := GetContract(private, c1Updated.Hash)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 2, len(c1Upper.Manifest.ABI.Methods)) require.Equal(t, 2, len(c1Upper.Manifest.ABI.Methods))
@ -152,7 +158,7 @@ func TestManagement_GetNEP17Contracts(t *testing.T) {
_, err = private.Persist() _, err = private.Persist()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, []util.Uint160{c1.Hash}, mgmt.GetNEP17Contracts(d)) require.Equal(t, []util.Uint160{c1.Hash}, mgmt.GetNEP17Contracts(d))
c1Lower, err = mgmt.GetContract(d, c1.Hash) c1Lower, err = GetContract(d, c1.Hash)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 2, len(c1Lower.Manifest.ABI.Methods)) require.Equal(t, 2, len(c1Lower.Manifest.ABI.Methods))
} }

View file

@ -8,6 +8,7 @@ import (
"github.com/nspcc-dev/neo-go/internal/contracts" "github.com/nspcc-dev/neo-go/internal/contracts"
"github.com/nspcc-dev/neo-go/pkg/core/chaindump" "github.com/nspcc-dev/neo-go/pkg/core/chaindump"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
@ -556,6 +557,41 @@ func TestManagement_GetContract(t *testing.T) {
t.Run("positive", func(t *testing.T) { t.Run("positive", func(t *testing.T) {
managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
}) })
t.Run("by ID, bad parameter type", func(t *testing.T) {
managementInvoker.InvokeFail(t, "invalid conversion: Array/Integer", "getContractById", []interface{}{int64(1)})
})
t.Run("by ID, bad num", func(t *testing.T) {
managementInvoker.InvokeFail(t, "id is not a correct int32", "getContractById", []byte{1, 2, 3, 4, 5})
})
t.Run("by ID, positive", func(t *testing.T) {
managementInvoker.Invoke(t, si, "getContractById", cs1.ID)
})
t.Run("by ID, native", func(t *testing.T) {
csm := managementInvoker.Executor.Chain.GetContractState(managementInvoker.Hash)
require.NotNil(t, csm)
sim, err := csm.ToStackItem()
require.NoError(t, err)
managementInvoker.Invoke(t, sim, "getContractById", -1)
})
t.Run("by ID, empty", func(t *testing.T) {
managementInvoker.Invoke(t, stackitem.Null{}, "getContractById", -100)
})
t.Run("contract hashes", func(t *testing.T) {
w := io.NewBufBinWriter()
emit.AppCall(w.BinWriter, managementInvoker.Hash, "getContractHashes", callflag.All)
emit.Opcodes(w.BinWriter, opcode.DUP) // Iterator.
emit.Syscall(w.BinWriter, interopnames.SystemIteratorNext)
emit.Opcodes(w.BinWriter, opcode.ASSERT) // Has one element.
emit.Opcodes(w.BinWriter, opcode.DUP) // Iterator.
emit.Syscall(w.BinWriter, interopnames.SystemIteratorValue)
emit.Opcodes(w.BinWriter, opcode.SWAP) // Iterator to the top.
emit.Syscall(w.BinWriter, interopnames.SystemIteratorNext)
emit.Opcodes(w.BinWriter, opcode.NOT)
emit.Opcodes(w.BinWriter, opcode.ASSERT) // No more elements, single value left on the stack.
require.NoError(t, w.Err)
h := managementInvoker.InvokeScript(t, w.Bytes(), managementInvoker.Signers)
managementInvoker.Executor.CheckHalt(t, h, stackitem.NewStruct([]stackitem.Item{stackitem.Make([]byte{0, 0, 0, 1}), stackitem.Make(cs1.Hash.BytesBE())}))
})
} }
func TestManagement_ContractDestroy(t *testing.T) { func TestManagement_ContractDestroy(t *testing.T) {

View file

@ -17,7 +17,6 @@ const (
// DataMPTAux is used to store additional MPT data like height-root // DataMPTAux is used to store additional MPT data like height-root
// mappings and local/validated heights. // mappings and local/validated heights.
DataMPTAux KeyPrefix = 0x04 DataMPTAux KeyPrefix = 0x04
STContractID KeyPrefix = 0x51
STStorage KeyPrefix = 0x70 STStorage KeyPrefix = 0x70
// STTempStorage is used to store contract storage items during state sync process // STTempStorage is used to store contract storage items during state sync process
// in order not to mess up the previous state which has its own items stored by // in order not to mess up the previous state which has its own items stored by

View file

@ -7,12 +7,21 @@ package management
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop" "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/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal" "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
) )
// Hash represents Management contract hash. // Hash represents Management contract hash.
const Hash = "\xfd\xa3\xfa\x43\x46\xea\x53\x2a\x25\x8f\xc4\x97\xdd\xad\xdb\x64\x37\xc9\xfd\xff" const Hash = "\xfd\xa3\xfa\x43\x46\xea\x53\x2a\x25\x8f\xc4\x97\xdd\xad\xdb\x64\x37\xc9\xfd\xff"
// IDHash is an ID/Hash pair returned by the iterator from the GetContractHashes method.
type IDHash struct {
// ID is a 32-bit number, but it's represented in big endian form
// natively, because that's the key scheme used by ContractManagement.
ID []byte
Hash interop.Hash160
}
// Deploy represents `deploy` method of Management native contract. // Deploy represents `deploy` method of Management native contract.
func Deploy(script, manifest []byte) *Contract { func Deploy(script, manifest []byte) *Contract {
return neogointernal.CallWithToken(Hash, "deploy", return neogointernal.CallWithToken(Hash, "deploy",
@ -35,6 +44,19 @@ func GetContract(addr interop.Hash160) *Contract {
return neogointernal.CallWithToken(Hash, "getContract", int(contract.ReadStates), addr).(*Contract) return neogointernal.CallWithToken(Hash, "getContract", int(contract.ReadStates), addr).(*Contract)
} }
// GetContractByID represents `getContractById` method of the Management native contract.
func GetContractByID(id int) *Contract {
return neogointernal.CallWithToken(Hash, "getContractById", int(contract.ReadStates), id).(*Contract)
}
// GetContractHashes represents `getContractHashes` method of the Management
// native contract. It returns an Iterator over the list of non-native contract
// hashes. Each iterator value can be cast to IDHash. Use [iterator] interop
// package to work with the returned Iterator.
func GetContractHashes() iterator.Iterator {
return neogointernal.CallWithToken(Hash, "getContractHashes", int(contract.ReadStates)).(iterator.Iterator)
}
// GetMinimumDeploymentFee represents `getMinimumDeploymentFee` method of Management native contract. // GetMinimumDeploymentFee represents `getMinimumDeploymentFee` method of Management native contract.
func GetMinimumDeploymentFee() int { func GetMinimumDeploymentFee() int {
return neogointernal.CallWithToken(Hash, "getMinimumDeploymentFee", int(contract.ReadStates)).(int) return neogointernal.CallWithToken(Hash, "getMinimumDeploymentFee", int(contract.ReadStates)).(int)

View file

@ -7,10 +7,12 @@ various methods to perform state-changing calls.
package management package management
import ( import (
"encoding/binary"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/big" "math/big"
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -20,11 +22,15 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
// Invoker is used by ContractReader to call various methods. // Invoker is used by ContractReader to call various methods.
type Invoker interface { type Invoker interface {
Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error) Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error)
CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...interface{}) (*result.Invoke, error)
TerminateSession(sessionID uuid.UUID) error
TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error)
} }
// Actor is used by Contract to create and send transactions. // Actor is used by Contract to create and send transactions.
@ -55,6 +61,19 @@ type Contract struct {
actor Actor actor Actor
} }
// IDHash is an ID/Hash pair returned by the iterator from the GetContractHashes method.
type IDHash struct {
ID int32
Hash util.Uint160
}
// HashesIterator is used for iterating over GetContractHashes results.
type HashesIterator struct {
client Invoker
session uuid.UUID
iterator result.Iterator
}
// Hash stores the hash of the native ContractManagement contract. // Hash stores the hash of the native ContractManagement contract.
var Hash = state.CreateNativeContractHash(nativenames.Management) var Hash = state.CreateNativeContractHash(nativenames.Management)
@ -83,7 +102,16 @@ func New(actor Actor) *Contract {
// getcontractstate RPC API that has more options and works faster than going // getcontractstate RPC API that has more options and works faster than going
// via contract invocation. // via contract invocation.
func (c *ContractReader) GetContract(hash util.Uint160) (*state.Contract, error) { func (c *ContractReader) GetContract(hash util.Uint160) (*state.Contract, error) {
itm, err := unwrap.Item(c.invoker.Call(Hash, "getContract", hash)) return unwrapContract(c.invoker.Call(Hash, "getContract", hash))
}
// GetContractByID allows to get contract data from its ID.
func (c *ContractReader) GetContractByID(id int32) (*state.Contract, error) {
return unwrapContract(c.invoker.Call(Hash, "getContractById", id))
}
func unwrapContract(r *result.Invoke, err error) (*state.Contract, error) {
itm, err := unwrap.Item(r, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -95,6 +123,88 @@ func (c *ContractReader) GetContract(hash util.Uint160) (*state.Contract, error)
return res, nil return res, nil
} }
// GetContractHashes returns an iterator that allows to retrieve all ID-hash
// mappings for non-native contracts. It depends on the server to provide proper
// session-based iterator, but can also work with expanded one.
func (c *ContractReader) GetContractHashes() (*HashesIterator, error) {
sess, iter, err := unwrap.SessionIterator(c.invoker.Call(Hash, "getContractHashes"))
if err != nil {
return nil, err
}
return &HashesIterator{
client: c.invoker,
iterator: iter,
session: sess,
}, nil
}
// GetContractHashesExpanded is similar to GetContractHashes (uses the same
// contract method), but can be useful if the server used doesn't support
// sessions and doesn't expand iterators. It creates a script that will get num
// of result items from the iterator right in the VM and return them to you. It's
// only limited by VM stack and GAS available for RPC invocations.
func (c *ContractReader) GetContractHashesExpanded(num int) ([]IDHash, error) {
arr, err := unwrap.Array(c.invoker.CallAndExpandIterator(Hash, "getContractHashes", num))
if err != nil {
return nil, err
}
return itemsToIDHashes(arr)
}
// Next returns the next set of elements from the iterator (up to num of them).
// It can return less than num elements in case iterator doesn't have that many
// or zero elements if the iterator has no more elements or the session is
// expired.
func (h *HashesIterator) Next(num int) ([]IDHash, error) {
items, err := h.client.TraverseIterator(h.session, &h.iterator, num)
if err != nil {
return nil, err
}
return itemsToIDHashes(items)
}
// Terminate closes the iterator session used by HashesIterator (if it's
// session-based).
func (h *HashesIterator) Terminate() error {
if h.iterator.ID == nil {
return nil
}
return h.client.TerminateSession(h.session)
}
func itemsToIDHashes(arr []stackitem.Item) ([]IDHash, error) {
res := make([]IDHash, len(arr))
for i, itm := range arr {
str, ok := itm.Value().([]stackitem.Item)
if !ok {
return nil, fmt.Errorf("item #%d is not a structure %T", i, itm.Value())
}
if len(str) != 2 {
return nil, fmt.Errorf("item #%d has wrong length", i)
}
bi, err := str[0].TryBytes()
if err != nil {
return nil, fmt.Errorf("item #%d has wrong ID: %w", i, err)
}
if len(bi) != 4 {
return nil, fmt.Errorf("item #%d has wrong ID: bad length", i)
}
id := int32(binary.BigEndian.Uint32(bi))
hb, err := str[1].TryBytes()
if err != nil {
return nil, fmt.Errorf("item #%d has wrong hash: %w", i, err)
}
u160, err := util.Uint160DecodeBytesBE(hb)
if err != nil {
return nil, fmt.Errorf("item #%d has wrong hash: %w", i, err)
}
res[i].ID = id
res[i].Hash = u160
}
return res, nil
}
// GetMinimumDeploymentFee returns the minimal amount of GAS needed to deploy a // GetMinimumDeploymentFee returns the minimal amount of GAS needed to deploy a
// contract on the network. // contract on the network.
func (c *ContractReader) GetMinimumDeploymentFee() (*big.Int, error) { func (c *ContractReader) GetMinimumDeploymentFee() (*big.Int, error) {

View file

@ -5,6 +5,7 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
@ -43,6 +44,15 @@ func (t *testAct) MakeUnsignedRun(script []byte, attrs []transaction.Attribute)
func (t *testAct) SendRun(script []byte) (util.Uint256, uint32, error) { func (t *testAct) SendRun(script []byte) (util.Uint256, uint32, error) {
return t.txh, t.vub, t.err return t.txh, t.vub, t.err
} }
func (t *testAct) CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...interface{}) (*result.Invoke, error) {
return t.res, t.err
}
func (t *testAct) TerminateSession(sessionID uuid.UUID) error {
return t.err
}
func (t *testAct) TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error) {
return t.res.Stack, t.err
}
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
ta := new(testAct) ta := new(testAct)
@ -51,6 +61,8 @@ func TestReader(t *testing.T) {
ta.err = errors.New("") ta.err = errors.New("")
_, err := man.GetContract(util.Uint160{1, 2, 3}) _, err := man.GetContract(util.Uint160{1, 2, 3})
require.Error(t, err) require.Error(t, err)
_, err = man.GetContractByID(1)
require.Error(t, err)
_, err = man.GetMinimumDeploymentFee() _, err = man.GetMinimumDeploymentFee()
require.Error(t, err) require.Error(t, err)
_, err = man.HasMethod(util.Uint160{1, 2, 3}, "method", 0) _, err = man.HasMethod(util.Uint160{1, 2, 3}, "method", 0)
@ -65,6 +77,8 @@ func TestReader(t *testing.T) {
} }
_, err = man.GetContract(util.Uint160{1, 2, 3}) _, err = man.GetContract(util.Uint160{1, 2, 3})
require.Error(t, err) require.Error(t, err)
_, err = man.GetContractByID(1)
require.Error(t, err)
fee, err := man.GetMinimumDeploymentFee() fee, err := man.GetMinimumDeploymentFee()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, big.NewInt(42), fee) require.Equal(t, big.NewInt(42), fee)
@ -80,6 +94,8 @@ func TestReader(t *testing.T) {
} }
_, err = man.GetContract(util.Uint160{1, 2, 3}) _, err = man.GetContract(util.Uint160{1, 2, 3})
require.Error(t, err) require.Error(t, err)
_, err = man.GetContractByID(1)
require.Error(t, err)
hm, err = man.HasMethod(util.Uint160{1, 2, 3}, "method", 0) hm, err = man.HasMethod(util.Uint160{1, 2, 3}, "method", 0)
require.NoError(t, err) require.NoError(t, err)
require.False(t, hm) require.False(t, hm)
@ -92,6 +108,8 @@ func TestReader(t *testing.T) {
} }
_, err = man.GetContract(util.Uint160{1, 2, 3}) _, err = man.GetContract(util.Uint160{1, 2, 3})
require.Error(t, err) require.Error(t, err)
_, err = man.GetContractByID(1)
require.Error(t, err)
nefFile, _ := nef.NewFile([]byte{1, 2, 3}) nefFile, _ := nef.NewFile([]byte{1, 2, 3})
nefBytes, _ := nefFile.Bytes() nefBytes, _ := nefFile.Bytes()
@ -114,6 +132,109 @@ func TestReader(t *testing.T) {
require.Equal(t, int32(1), cs.ID) require.Equal(t, int32(1), cs.ID)
require.Equal(t, uint16(0), cs.UpdateCounter) require.Equal(t, uint16(0), cs.UpdateCounter)
require.Equal(t, util.Uint160{1, 2, 3}, cs.Hash) require.Equal(t, util.Uint160{1, 2, 3}, cs.Hash)
cs2, err := man.GetContractByID(1)
require.NoError(t, err)
require.Equal(t, cs, cs2)
}
func TestGetContractHashes(t *testing.T) {
ta := &testAct{}
man := NewReader(ta)
ta.err = errors.New("")
_, err := man.GetContractHashes()
require.Error(t, err)
_, err = man.GetContractHashesExpanded(5)
require.Error(t, err)
ta.err = nil
iid := uuid.New()
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.NewInterop(result.Iterator{
ID: &iid,
}),
},
}
_, err = man.GetContractHashes()
require.Error(t, err)
// Session-based iterator.
sid := uuid.New()
ta.res = &result.Invoke{
Session: sid,
State: "HALT",
Stack: []stackitem.Item{
stackitem.NewInterop(result.Iterator{
ID: &iid,
}),
},
}
iter, err := man.GetContractHashes()
require.NoError(t, err)
ta.res = &result.Invoke{
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make([]byte{0, 0, 0, 1}),
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()),
}),
},
}
vals, err := iter.Next(10)
require.NoError(t, err)
require.Equal(t, 1, len(vals))
require.Equal(t, IDHash{
ID: 1,
Hash: util.Uint160{1, 2, 3},
}, vals[0])
ta.err = errors.New("")
_, err = iter.Next(1)
require.Error(t, err)
err = iter.Terminate()
require.Error(t, err)
// Value-based iterator.
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.NewInterop(result.Iterator{
Values: []stackitem.Item{stackitem.NewStruct([]stackitem.Item{
stackitem.Make([]byte{0, 0, 0, 1}),
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()),
})},
}),
},
}
iter, err = man.GetContractHashes()
require.NoError(t, err)
ta.err = errors.New("")
err = iter.Terminate()
require.NoError(t, err)
// Expanded
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{stackitem.Make([]stackitem.Item{
stackitem.Make([]byte{0, 0, 0, 1}),
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()),
})}),
},
}
vals, err = man.GetContractHashesExpanded(5)
require.NoError(t, err)
require.Equal(t, 1, len(vals))
require.Equal(t, IDHash{
ID: 1,
Hash: util.Uint160{1, 2, 3},
}, vals[0])
} }
func TestSetMinimumDeploymentFee(t *testing.T) { func TestSetMinimumDeploymentFee(t *testing.T) {
@ -204,3 +325,31 @@ func TestDeploy(t *testing.T) {
// Unfortunately, manifest _always_ marshals successfully (or panics). // Unfortunately, manifest _always_ marshals successfully (or panics).
} }
func TestItemsToIDHashesErrors(t *testing.T) {
for name, input := range map[string][]stackitem.Item{
"not a struct": {stackitem.Make(1)},
"wrong length": {stackitem.Make([]stackitem.Item{})},
"wrong id": {stackitem.Make([]stackitem.Item{
stackitem.Make([]stackitem.Item{}),
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()),
})},
"lengthy id": {stackitem.Make([]stackitem.Item{
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()),
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()),
})},
"not a good hash": {stackitem.Make([]stackitem.Item{
stackitem.Make([]byte{0, 0, 0, 1}),
stackitem.Make([]stackitem.Item{}),
})},
"not a good u160 hash": {stackitem.Make([]stackitem.Item{
stackitem.Make([]byte{0, 0, 0, 1}),
stackitem.Make(util.Uint256{1, 2, 3}.BytesBE()),
})},
} {
t.Run(name, func(t *testing.T) {
_, err := itemsToIDHashes(input)
require.Error(t, err)
})
}
}

View file

@ -256,6 +256,9 @@ func TestClientManagementContract(t *testing.T) {
cs2, err := c.GetContractStateByHash(gas.Hash) cs2, err := c.GetContractStateByHash(gas.Hash)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, cs2, cs1) require.Equal(t, cs2, cs1)
cs1, err = manReader.GetContractByID(-6)
require.NoError(t, err)
require.Equal(t, cs2, cs1)
ret, err := manReader.HasMethod(gas.Hash, "transfer", 4) ret, err := manReader.HasMethod(gas.Hash, "transfer", 4)
require.NoError(t, err) require.NoError(t, err)
@ -275,6 +278,25 @@ func TestClientManagementContract(t *testing.T) {
}}) }})
require.NoError(t, err) require.NoError(t, err)
ids, err := manReader.GetContractHashesExpanded(10)
require.NoError(t, err)
ctrs := make([]management.IDHash, 0)
for i, s := range []string{testContractHash, verifyContractHash, verifyWithArgsContractHash, nnsContractHash, nfsoContractHash, storageContractHash} {
h, err := util.Uint160DecodeStringLE(s)
require.NoError(t, err)
ctrs = append(ctrs, management.IDHash{ID: int32(i) + 1, Hash: h})
}
require.Equal(t, ctrs, ids)
iter, err := manReader.GetContractHashes()
require.NoError(t, err)
ids, err = iter.Next(3)
require.NoError(t, err)
require.Equal(t, ctrs[:3], ids)
ids, err = iter.Next(10)
require.NoError(t, err)
require.Equal(t, ctrs[3:], ids)
man := management.New(act) man := management.New(act)
txfee, err := man.SetMinimumDeploymentFeeUnsigned(big.NewInt(1 * 1_0000_0000)) txfee, err := man.SetMinimumDeploymentFeeUnsigned(big.NewInt(1 * 1_0000_0000))

View file

@ -82,7 +82,7 @@ const (
faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60" faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60"
faultedTxBlock uint32 = 23 faultedTxBlock uint32 = 23
invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA" invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA"
block20StateRootLE = "b49a045246bf3bb90248ed538dd21e67d782a9242c52f31dfdef3da65ecd87c1" block20StateRootLE = "13620fef0fb28060523a0b73ce574ee4658fca5d0d24078a73e74a349c37a854"
) )
var ( var (
@ -2069,6 +2069,15 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
} }
t.Run("ByHeight", func(t *testing.T) { testRoot(t, strconv.FormatInt(5, 10)) }) t.Run("ByHeight", func(t *testing.T) { testRoot(t, strconv.FormatInt(5, 10)) })
t.Run("ByHash", func(t *testing.T) { testRoot(t, `"`+chain.GetHeaderHash(5).StringLE()+`"`) }) t.Run("ByHash", func(t *testing.T) { testRoot(t, `"`+chain.GetHeaderHash(5).StringLE()+`"`) })
t.Run("20", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getstateroot", "params": [20]}`
body := doRPCCall(rpc, httpSrv.URL, t)
rawRes := checkErrGetResult(t, body, false)
res := &state.MPTRoot{}
require.NoError(t, json.Unmarshal(rawRes, res))
require.Equal(t, block20StateRootLE, res.Root.StringLE())
})
}) })
t.Run("getstate", func(t *testing.T) { t.Run("getstate", func(t *testing.T) {
testGetState := func(t *testing.T, p string, expected string) { testGetState := func(t *testing.T, p string, expected string) {