Merge pull request #3155 from nspcc-dev/apptr-pricing

*: introduce Policy attributes pricing
This commit is contained in:
Roman Khimov 2023-11-21 15:44:40 +03:00 committed by GitHub
commit 28ee1621b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 447 additions and 246 deletions

View file

@ -57,4 +57,4 @@ NeoGo retains certain deprecated error codes: `neorpc.ErrCompatGeneric`,
`neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the `neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the
neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions). neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions).
Removal of the deprecated RPC error codes is planned once all nodes adopt the new error standard. Removal of the deprecated RPC error codes is planned once all nodes adopt the new error standard.

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -4,7 +4,7 @@ go 1.19
require ( require (
github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
) )

View file

@ -200,8 +200,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.102.1-0.20231020181554-d89c8801d689 h1:WnEdGAQwaW0C8wnNnQZ+rM/JfFKZDSTOqwm8cS0TOdk= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 h1:WnEdGAQwaW0C8wnNnQZ+rM/JfFKZDSTOqwm8cS0TOdk=
github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=
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 v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -214,7 +214,7 @@ github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c h1:uyK5aLbAhrnZtnvo
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg= github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg=
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
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/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=
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 v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

2
go.mod
View file

@ -14,7 +14,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-20230515113611-25db6ba61d5c github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c
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-20231120162333-406c9f8b9214 github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11
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

@ -229,8 +229,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaF
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
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/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/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM=
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=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle
go 1.19 go 1.19
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=

View file

@ -25,6 +25,7 @@ import (
// Ledger is an interface that abstracts the implementation of the blockchain. // Ledger is an interface that abstracts the implementation of the blockchain.
type Ledger interface { type Ledger interface {
BlockHeight() uint32 BlockHeight() uint32
CalculateAttributesFee(tx *transaction.Transaction) int64
FeePerByte() int64 FeePerByte() int64
GetBaseExecFee() int64 GetBaseExecFee() int64
GetHeader(hash util.Uint256) (*block.Header, error) GetHeader(hash util.Uint256) (*block.Header, error)
@ -135,7 +136,7 @@ func signTxGeneric(bc Ledger, sign func(hash.Hashable) []byte, verif []byte, txs
netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), verif) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), verif)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * bc.FeePerByte() tx.NetworkFee += int64(size)*bc.FeePerByte() + bc.CalculateAttributesFee(tx)
tx.Scripts = []transaction.Witness{{ tx.Scripts = []transaction.Witness{{
InvocationScript: sign(tx), InvocationScript: sign(tx),
VerificationScript: verif, VerificationScript: verif,

View file

@ -123,6 +123,14 @@ func TestLedgerVMStates(t *testing.T) {
require.EqualValues(t, ledger.BreakState, vmstate.Break) require.EqualValues(t, ledger.BreakState, vmstate.Break)
} }
func TestPolicyAttributeType(t *testing.T) {
require.EqualValues(t, policy.HighPriorityT, transaction.HighPriority)
require.EqualValues(t, policy.OracleResponseT, transaction.OracleResponseT)
require.EqualValues(t, policy.NotValidBeforeT, transaction.NotValidBeforeT)
require.EqualValues(t, policy.ConflictsT, transaction.ConflictsT)
require.EqualValues(t, policy.NotaryAssistedT, transaction.NotaryAssistedT)
}
type nativeTestCase struct { type nativeTestCase struct {
method string method string
params []string params []string
@ -179,6 +187,8 @@ func TestNativeHelpersCompile(t *testing.T) {
{"setFeePerByte", []string{"42"}}, {"setFeePerByte", []string{"42"}},
{"setStoragePrice", []string{"42"}}, {"setStoragePrice", []string{"42"}},
{"unblockAccount", []string{u160}}, {"unblockAccount", []string{u160}},
{"getAttributeFee", []string{"1"}},
{"setAttributeFee", []string{"1", "123"}},
}) })
runNativeTestCases(t, cs.Ledger.ContractMD, "ledger", []nativeTestCase{ runNativeTestCases(t, cs.Ledger.ContractMD, "ledger", []nativeTestCase{
{"currentHash", nil}, {"currentHash", nil},
@ -197,8 +207,6 @@ func TestNativeHelpersCompile(t *testing.T) {
{"expirationOf", []string{u160}}, {"expirationOf", []string{u160}},
{"getMaxNotValidBeforeDelta", nil}, {"getMaxNotValidBeforeDelta", nil},
{"setMaxNotValidBeforeDelta", []string{"42"}}, {"setMaxNotValidBeforeDelta", []string{"42"}},
{"getNotaryServiceFeePerKey", nil},
{"setNotaryServiceFeePerKey", []string{"42"}},
}) })
runNativeTestCases(t, cs.Management.ContractMD, "management", []nativeTestCase{ runNativeTestCases(t, cs.Management.ContractMD, "management", []nativeTestCase{
{"deploy", []string{"nil", "nil"}}, {"deploy", []string{"nil", "nil"}},

View file

@ -53,6 +53,7 @@ type Ledger interface {
SubscribeForBlocks(ch chan *coreb.Block) SubscribeForBlocks(ch chan *coreb.Block)
UnsubscribeFromBlocks(ch chan *coreb.Block) UnsubscribeFromBlocks(ch chan *coreb.Block)
GetBaseExecFee() int64 GetBaseExecFee() int64
CalculateAttributesFee(tx *transaction.Transaction) int64
interop.Ledger interop.Ledger
mempool.Feer mempool.Feer
} }

View file

@ -592,7 +592,7 @@ func signTx(t *testing.T, bc Ledger, txs ...*transaction.Transaction) {
netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript)
tx.NetworkFee += +netFee tx.NetworkFee += +netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * bc.FeePerByte() tx.NetworkFee += int64(size)*bc.FeePerByte() + bc.CalculateAttributesFee(tx)
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
for _, key := range privNetKeys { for _, key := range privNetKeys {

View file

@ -2054,10 +2054,10 @@ func (bc *Blockchain) GetNotaryBalance(acc util.Uint160) *big.Int {
return bc.contracts.Notary.BalanceOf(bc.dao, acc) return bc.contracts.Notary.BalanceOf(bc.dao, acc)
} }
// GetNotaryServiceFeePerKey returns NotaryServiceFeePerKey which is a reward per // GetNotaryServiceFeePerKey returns a NotaryAssisted transaction attribute fee
// notary request key for designated notary nodes. // per key which is a reward per notary request key for designated notary nodes.
func (bc *Blockchain) GetNotaryServiceFeePerKey() int64 { func (bc *Blockchain) GetNotaryServiceFeePerKey() int64 {
return bc.contracts.Notary.GetNotaryServiceFeePerKey(bc.dao) return bc.contracts.Policy.GetAttributeFeeInternal(bc.dao, transaction.NotaryAssistedT)
} }
// GetNotaryContractScriptHash returns Notary native contract hash. // GetNotaryContractScriptHash returns Notary native contract hash.
@ -2479,14 +2479,7 @@ func (bc *Blockchain) verifyAndPoolTx(t *transaction.Transaction, pool *mempool.
if size > transaction.MaxTransactionSize { if size > transaction.MaxTransactionSize {
return fmt.Errorf("%w: (%d > MaxTransactionSize %d)", ErrTxTooBig, size, transaction.MaxTransactionSize) return fmt.Errorf("%w: (%d > MaxTransactionSize %d)", ErrTxTooBig, size, transaction.MaxTransactionSize)
} }
needNetworkFee := int64(size) * bc.FeePerByte() needNetworkFee := int64(size)*bc.FeePerByte() + bc.CalculateAttributesFee(t)
if bc.P2PSigExtensionsEnabled() {
attrs := t.GetAttributes(transaction.NotaryAssistedT)
if len(attrs) != 0 {
na := attrs[0].Value.(*transaction.NotaryAssisted)
needNetworkFee += (int64(na.NKeys) + 1) * bc.contracts.Notary.GetNotaryServiceFeePerKey(bc.dao)
}
}
netFee := t.NetworkFee - needNetworkFee netFee := t.NetworkFee - needNetworkFee
if netFee < 0 { if netFee < 0 {
return fmt.Errorf("%w: net fee is %v, need %v", ErrTxSmallNetworkFee, t.NetworkFee, needNetworkFee) return fmt.Errorf("%w: net fee is %v, need %v", ErrTxSmallNetworkFee, t.NetworkFee, needNetworkFee)
@ -2502,7 +2495,7 @@ func (bc *Blockchain) verifyAndPoolTx(t *transaction.Transaction, pool *mempool.
return err return err
} }
} }
err = bc.verifyTxWitnesses(t, nil, isPartialTx) err = bc.verifyTxWitnesses(t, nil, isPartialTx, netFee)
if err != nil { if err != nil {
return err return err
} }
@ -2530,6 +2523,27 @@ func (bc *Blockchain) verifyAndPoolTx(t *transaction.Transaction, pool *mempool.
return nil return nil
} }
// CalculateAttributesFee returns network fee for all transaction attributes that should be
// paid according to native Policy.
func (bc *Blockchain) CalculateAttributesFee(tx *transaction.Transaction) int64 {
var feeSum int64
for _, attr := range tx.Attributes {
base := bc.contracts.Policy.GetAttributeFeeInternal(bc.dao, attr.Type)
switch attr.Type {
case transaction.ConflictsT:
feeSum += base * int64(len(tx.Signers))
case transaction.NotaryAssistedT:
if bc.P2PSigExtensionsEnabled() {
na := attr.Value.(*transaction.NotaryAssisted)
feeSum += base * (int64(na.NKeys) + 1)
}
default:
feeSum += base
}
}
return feeSum
}
func (bc *Blockchain) verifyTxAttributes(d *dao.Simple, tx *transaction.Transaction, isPartialTx bool) error { func (bc *Blockchain) verifyTxAttributes(d *dao.Simple, tx *transaction.Transaction, isPartialTx bool) error {
for i := range tx.Attributes { for i := range tx.Attributes {
switch attrType := tx.Attributes[i].Type; attrType { switch attrType := tx.Attributes[i].Type; attrType {
@ -2889,17 +2903,17 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
// transaction. It can reorder them by ScriptHash, because that's required to // transaction. It can reorder them by ScriptHash, because that's required to
// match a slice of script hashes from the Blockchain. Block parameter // match a slice of script hashes from the Blockchain. Block parameter
// is used for easy interop access and can be omitted for transactions that are // is used for easy interop access and can be omitted for transactions that are
// not yet added into any block. // not yet added into any block. verificationFee argument can be provided to
// restrict the maximum amount of GAS allowed to spend on transaction
// verification.
// Golang implementation of VerifyWitnesses method in C# (https://github.com/neo-project/neo/blob/master/neo/SmartContract/Helper.cs#L87). // Golang implementation of VerifyWitnesses method in C# (https://github.com/neo-project/neo/blob/master/neo/SmartContract/Helper.cs#L87).
func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block.Block, isPartialTx bool) error { func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block.Block, isPartialTx bool, verificationFee ...int64) error {
interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t) interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t)
gasLimit := t.NetworkFee - int64(t.Size())*bc.FeePerByte() var gasLimit int64
if bc.P2PSigExtensionsEnabled() { if len(verificationFee) == 0 {
attrs := t.GetAttributes(transaction.NotaryAssistedT) gasLimit = t.NetworkFee - int64(t.Size())*bc.FeePerByte() - bc.CalculateAttributesFee(t)
if len(attrs) != 0 { } else {
na := attrs[0].Value.(*transaction.NotaryAssisted) gasLimit = verificationFee[0]
gasLimit -= (int64(na.NKeys) + 1) * bc.contracts.Notary.GetNotaryServiceFeePerKey(bc.dao)
}
} }
for i := range t.Signers { for i := range t.Signers {
gasConsumed, err := bc.verifyHashAgainstScript(t.Signers[i].Account, &t.Scripts[i], interopCtx, gasLimit) gasConsumed, err := bc.verifyHashAgainstScript(t.Signers[i].Account, &t.Scripts[i], interopCtx, gasLimit)

View file

@ -74,10 +74,11 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions) gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions)
neo := newNEO(cfg) neo := newNEO(cfg)
policy := newPolicy() policy := newPolicy(cfg.P2PSigExtensions)
neo.GAS = gas neo.GAS = gas
neo.Policy = policy neo.Policy = policy
gas.NEO = neo gas.NEO = neo
gas.Policy = policy
mgmt.NEO = neo mgmt.NEO = neo
mgmt.Policy = policy mgmt.Policy = policy
policy.NEO = neo policy.NEO = neo
@ -104,8 +105,8 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
notary.GAS = gas notary.GAS = gas
notary.NEO = neo notary.NEO = neo
notary.Desig = desig notary.Desig = desig
notary.Policy = policy
cs.Notary = notary cs.Notary = notary
gas.Notary = notary
cs.Contracts = append(cs.Contracts, notary) cs.Contracts = append(cs.Contracts, notary)
} }

View file

@ -17,7 +17,7 @@ import (
func TestDeployGetUpdateDestroyContract(t *testing.T) { func TestDeployGetUpdateDestroyContract(t *testing.T) {
mgmt := newManagement() mgmt := newManagement()
mgmt.Policy = newPolicy() mgmt.Policy = newPolicy(false)
d := dao.NewSimple(storage.NewMemoryStore(), false) d := dao.NewSimple(storage.NewMemoryStore(), false)
ic := &interop.Context{DAO: d} ic := &interop.Context{DAO: d}
err := mgmt.Initialize(ic) err := mgmt.Initialize(ic)
@ -97,7 +97,7 @@ func TestManagement_Initialize(t *testing.T) {
func TestManagement_GetNEP17Contracts(t *testing.T) { func TestManagement_GetNEP17Contracts(t *testing.T) {
mgmt := newManagement() mgmt := newManagement()
mgmt.Policy = newPolicy() mgmt.Policy = newPolicy(false)
d := dao.NewSimple(storage.NewMemoryStore(), false) d := dao.NewSimple(storage.NewMemoryStore(), false)
err := mgmt.Initialize(&interop.Context{DAO: d}) err := mgmt.Initialize(&interop.Context{DAO: d})
require.NoError(t, err) require.NoError(t, err)

View file

@ -18,9 +18,8 @@ import (
// GAS represents GAS native contract. // GAS represents GAS native contract.
type GAS struct { type GAS struct {
nep17TokenNative nep17TokenNative
NEO *NEO NEO *NEO
// Notary is a native Notary contract. It is set only when P2PSigExtensions are on. Policy *Policy
Notary *Notary
initialSupply int64 initialSupply int64
p2pSigExtensionsEnabled bool p2pSigExtensionsEnabled bool
@ -124,7 +123,7 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
attrs := tx.GetAttributes(transaction.NotaryAssistedT) attrs := tx.GetAttributes(transaction.NotaryAssistedT)
if len(attrs) != 0 { if len(attrs) != 0 {
na := attrs[0].Value.(*transaction.NotaryAssisted) na := attrs[0].Value.(*transaction.NotaryAssisted)
netFee -= (int64(na.NKeys) + 1) * g.Notary.GetNotaryServiceFeePerKey(ic.DAO) netFee -= (int64(na.NKeys) + 1) * g.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
} }
} }
} }

View file

@ -347,18 +347,30 @@ func toUint160(s stackitem.Item) util.Uint160 {
return u return u
} }
func toUint32(s stackitem.Item) uint32 { func toUint64(s stackitem.Item) uint64 {
bigInt := toBigInt(s) bigInt := toBigInt(s)
if !bigInt.IsUint64() { if !bigInt.IsUint64() {
panic("bigint is not an uint64") panic("bigint is not a uint64")
} }
uint64Value := bigInt.Uint64() return bigInt.Uint64()
}
func toUint32(s stackitem.Item) uint32 {
uint64Value := toUint64(s)
if uint64Value > math.MaxUint32 { if uint64Value > math.MaxUint32 {
panic("bigint does not fit into uint32") panic("bigint does not fit into uint32")
} }
return uint32(uint64Value) return uint32(uint64Value)
} }
func toUint8(s stackitem.Item) uint8 {
uint64Value := toUint64(s)
if uint64Value > math.MaxUint8 {
panic("bigint does not fit into uint8")
}
return uint8(uint64Value)
}
func toInt64(s stackitem.Item) int64 { func toInt64(s stackitem.Item) int64 {
bigInt := toBigInt(s) bigInt := toBigInt(s)
if !bigInt.IsInt64() { if !bigInt.IsInt64() {

View file

@ -38,16 +38,6 @@ func TestNotary_MaxNotValidBeforeDeltaCache(t *testing.T) {
testGetSetCache(t, c, "MaxNotValidBeforeDelta", 140) testGetSetCache(t, c, "MaxNotValidBeforeDelta", 140)
} }
func TestNotary_NotaryServiceFeePerKey(t *testing.T) {
c := newNotaryClient(t)
testGetSet(t, c, "NotaryServiceFeePerKey", 1000_0000, 0, 0)
}
func TestNotary_NotaryServiceFeePerKeyCache(t *testing.T) {
c := newNotaryClient(t)
testGetSetCache(t, c, "NotaryServiceFeePerKey", 1000_0000)
}
func TestNotary_Pipeline(t *testing.T) { func TestNotary_Pipeline(t *testing.T) {
notaryCommitteeInvoker := newNotaryClient(t) notaryCommitteeInvoker := newNotaryClient(t)
e := notaryCommitteeInvoker.Executor e := notaryCommitteeInvoker.Executor

View file

@ -7,8 +7,14 @@ import (
"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/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
"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/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"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
func newPolicyClient(t *testing.T) *neotest.ContractInvoker { func newPolicyClient(t *testing.T) *neotest.ContractInvoker {
@ -39,6 +45,67 @@ func TestPolicy_StoragePriceCache(t *testing.T) {
testGetSetCache(t, newPolicyClient(t), "StoragePrice", native.DefaultStoragePrice) testGetSetCache(t, newPolicyClient(t), "StoragePrice", native.DefaultStoragePrice)
} }
func TestPolicy_AttributeFee(t *testing.T) {
c := newPolicyClient(t)
getName := "getAttributeFee"
setName := "setAttributeFee"
randomInvoker := c.WithSigners(c.NewAccount(t))
committeeInvoker := c.WithSigners(c.Committee)
t.Run("set, not signed by committee", func(t *testing.T) {
randomInvoker.InvokeFail(t, "invalid committee signature", setName, byte(transaction.ConflictsT), 123)
})
t.Run("get, unknown attribute", func(t *testing.T) {
randomInvoker.InvokeFail(t, "invalid attribute type: 84", getName, byte(0x54))
})
t.Run("get, default value", func(t *testing.T) {
randomInvoker.Invoke(t, 0, getName, byte(transaction.ConflictsT))
})
t.Run("set, too large value", func(t *testing.T) {
committeeInvoker.InvokeFail(t, "out of range", setName, byte(transaction.ConflictsT), 10_0000_0001)
})
t.Run("set, unknown attribute", func(t *testing.T) {
committeeInvoker.InvokeFail(t, "invalid attribute type: 84", setName, 0x54, 5)
})
t.Run("set, success", func(t *testing.T) {
// Set and get in the same block.
txSet := committeeInvoker.PrepareInvoke(t, setName, byte(transaction.ConflictsT), 1)
txGet := randomInvoker.PrepareInvoke(t, getName, byte(transaction.ConflictsT))
c.AddNewBlock(t, txSet, txGet)
c.CheckHalt(t, txSet.Hash(), stackitem.Null{})
c.CheckHalt(t, txGet.Hash(), stackitem.Make(1))
// Get in the next block.
randomInvoker.Invoke(t, 1, getName, byte(transaction.ConflictsT))
})
}
func TestPolicy_AttributeFeeCache(t *testing.T) {
c := newPolicyClient(t)
getName := "getAttributeFee"
setName := "setAttributeFee"
committeeInvoker := c.WithSigners(c.Committee)
// Change fee, abort the transaction and check that contract cache wasn't persisted
// for FAULTed tx at the same block.
w := io.NewBufBinWriter()
emit.AppCall(w.BinWriter, committeeInvoker.Hash, setName, callflag.All, byte(transaction.ConflictsT), 5)
emit.Opcodes(w.BinWriter, opcode.ABORT)
tx1 := committeeInvoker.PrepareInvocation(t, w.Bytes(), committeeInvoker.Signers)
tx2 := committeeInvoker.PrepareInvoke(t, getName, byte(transaction.ConflictsT))
committeeInvoker.AddNewBlock(t, tx1, tx2)
committeeInvoker.CheckFault(t, tx1.Hash(), "ABORT")
committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(0))
// Change fee and check that change is available for the next tx.
tx1 = committeeInvoker.PrepareInvoke(t, setName, byte(transaction.ConflictsT), 5)
tx2 = committeeInvoker.PrepareInvoke(t, getName, byte(transaction.ConflictsT))
committeeInvoker.AddNewBlock(t, tx1, tx2)
committeeInvoker.CheckHalt(t, tx1.Hash())
committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(5))
}
func TestPolicy_BlockedAccounts(t *testing.T) { func TestPolicy_BlockedAccounts(t *testing.T) {
c := newPolicyClient(t) c := newPolicyClient(t)
e := c.Executor e := c.Executor

View file

@ -28,14 +28,14 @@ import (
// Notary represents Notary native contract. // Notary represents Notary native contract.
type Notary struct { type Notary struct {
interop.ContractMD interop.ContractMD
GAS *GAS GAS *GAS
NEO *NEO NEO *NEO
Desig *Designate Desig *Designate
Policy *Policy
} }
type NotaryCache struct { type NotaryCache struct {
maxNotValidBeforeDelta uint32 maxNotValidBeforeDelta uint32
notaryServiceFeePerKey int64
} }
// NotaryService is a Notary module interface. // NotaryService is a Notary module interface.
@ -48,15 +48,10 @@ const (
// prefixDeposit is a prefix for storing Notary deposits. // prefixDeposit is a prefix for storing Notary deposits.
prefixDeposit = 1 prefixDeposit = 1
defaultDepositDeltaTill = 5760 defaultDepositDeltaTill = 5760
defaultMaxNotValidBeforeDelta = 140 // 20 rounds for 7 validators, a little more than half an hour defaultMaxNotValidBeforeDelta = 140 // 20 rounds for 7 validators, a little more than half an hour
defaultNotaryServiceFeePerKey = 1000_0000 // 0.1 GAS
maxNotaryServiceFeePerKey = 1_0000_0000 // 1 GAS
) )
var ( var maxNotValidBeforeDeltaKey = []byte{10}
maxNotValidBeforeDeltaKey = []byte{10}
notaryServiceFeeKey = []byte{5}
)
var ( var (
_ interop.Contract = (*Notary)(nil) _ interop.Contract = (*Notary)(nil)
@ -122,15 +117,6 @@ func newNotary() *Notary {
md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 1<<15, callflag.States) md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 1<<15, callflag.States)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getNotaryServiceFeePerKey", smartcontract.IntegerType)
md = newMethodAndPrice(n.getNotaryServiceFeePerKey, 1<<15, callflag.ReadStates)
n.AddMethod(md, desc)
desc = newDescriptor("setNotaryServiceFeePerKey", smartcontract.VoidType,
manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(n.setNotaryServiceFeePerKey, 1<<15, callflag.States)
n.AddMethod(md, desc)
return n return n
} }
@ -142,11 +128,9 @@ func (n *Notary) Metadata() *interop.ContractMD {
// Initialize initializes Notary native contract and implements the Contract interface. // Initialize initializes Notary native contract and implements the Contract interface.
func (n *Notary) Initialize(ic *interop.Context) error { func (n *Notary) Initialize(ic *interop.Context) error {
setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta) setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta)
setIntWithKey(n.ID, ic.DAO, notaryServiceFeeKey, defaultNotaryServiceFeePerKey)
cache := &NotaryCache{ cache := &NotaryCache{
maxNotValidBeforeDelta: defaultMaxNotValidBeforeDelta, maxNotValidBeforeDelta: defaultMaxNotValidBeforeDelta,
notaryServiceFeePerKey: defaultNotaryServiceFeePerKey,
} }
ic.DAO.SetCache(n.ID, cache) ic.DAO.SetCache(n.ID, cache)
return nil return nil
@ -155,7 +139,6 @@ func (n *Notary) Initialize(ic *interop.Context) error {
func (n *Notary) InitializeCache(blockHeight uint32, d *dao.Simple) error { func (n *Notary) InitializeCache(blockHeight uint32, d *dao.Simple) error {
cache := &NotaryCache{ cache := &NotaryCache{
maxNotValidBeforeDelta: uint32(getIntWithKey(n.ID, d, maxNotValidBeforeDeltaKey)), maxNotValidBeforeDelta: uint32(getIntWithKey(n.ID, d, maxNotValidBeforeDeltaKey)),
notaryServiceFeePerKey: getIntWithKey(n.ID, d, notaryServiceFeeKey),
} }
d.SetCache(n.ID, cache) d.SetCache(n.ID, cache)
@ -197,7 +180,7 @@ func (n *Notary) OnPersist(ic *interop.Context) error {
if nFees == 0 { if nFees == 0 {
return nil return nil
} }
feePerKey := n.GetNotaryServiceFeePerKey(ic.DAO) feePerKey := n.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
singleReward := calculateNotaryReward(nFees, feePerKey, len(notaries)) singleReward := calculateNotaryReward(nFees, feePerKey, len(notaries))
for _, notary := range notaries { for _, notary := range notaries {
n.GAS.mint(ic, notary.GetScriptHash(), singleReward, false) n.GAS.mint(ic, notary.GetScriptHash(), singleReward, false)
@ -238,7 +221,7 @@ func (n *Notary) onPayment(ic *interop.Context, args []stackitem.Item) stackitem
if deposit != nil && till < deposit.Till { if deposit != nil && till < deposit.Till {
panic(fmt.Errorf("`till` shouldn't be less than the previous value %d", deposit.Till)) panic(fmt.Errorf("`till` shouldn't be less than the previous value %d", deposit.Till))
} }
feePerKey := n.GetNotaryServiceFeePerKey(ic.DAO) feePerKey := n.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
if deposit == nil { if deposit == nil {
if amount.Cmp(big.NewInt(2*feePerKey)) < 0 { if amount.Cmp(big.NewInt(2*feePerKey)) < 0 {
panic(fmt.Errorf("first deposit can not be less than %d, got %d", 2*feePerKey, amount.Int64())) panic(fmt.Errorf("first deposit can not be less than %d, got %d", 2*feePerKey, amount.Int64()))
@ -435,32 +418,6 @@ func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem
return stackitem.Null{} return stackitem.Null{}
} }
// getNotaryServiceFeePerKey is a Notary contract method and returns a reward per notary request key for notary nodes.
func (n *Notary) getNotaryServiceFeePerKey(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewBigInteger(big.NewInt(int64(n.GetNotaryServiceFeePerKey(ic.DAO))))
}
// GetNotaryServiceFeePerKey is an internal representation of Notary getNotaryServiceFeePerKey method.
func (n *Notary) GetNotaryServiceFeePerKey(dao *dao.Simple) int64 {
cache := dao.GetROCache(n.ID).(*NotaryCache)
return cache.notaryServiceFeePerKey
}
// setNotaryServiceFeePerKey is a Notary contract method and sets a reward per notary request key for notary nodes.
func (n *Notary) setNotaryServiceFeePerKey(ic *interop.Context, args []stackitem.Item) stackitem.Item {
value := toInt64(args[0])
if value < 0 || value > maxNotaryServiceFeePerKey {
panic("NotaryServiceFeePerKey value is out of range")
}
if !n.NEO.checkCommittee(ic) {
panic("invalid committee signature")
}
setIntWithKey(n.ID, ic.DAO, notaryServiceFeeKey, int64(value))
cache := ic.DAO.GetRWCache(n.ID).(*NotaryCache)
cache.notaryServiceFeePerKey = value
return stackitem.Null{}
}
// GetDepositFor returns state.Deposit for the account specified. It returns nil in case // GetDepositFor returns state.Deposit for the account specified. It returns nil in case
// the deposit is not found in the storage and panics in case of any other error. // the deposit is not found in the storage and panics in case of any other error.
func (n *Notary) GetDepositFor(dao *dao.Simple, acc util.Uint160) *state.Deposit { func (n *Notary) GetDepositFor(dao *dao.Simple, acc util.Uint160) *state.Deposit {

View file

@ -1,6 +1,7 @@
package native package native
import ( import (
"encoding/hex"
"fmt" "fmt"
"math/big" "math/big"
"sort" "sort"
@ -11,6 +12,7 @@ import (
"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"
"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/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "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/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
@ -24,6 +26,10 @@ const (
defaultExecFeeFactor = interop.DefaultBaseExecFee defaultExecFeeFactor = interop.DefaultBaseExecFee
defaultFeePerByte = 1000 defaultFeePerByte = 1000
defaultMaxVerificationGas = 1_50000000 defaultMaxVerificationGas = 1_50000000
// defaultAttributeFee is a default fee for a transaction attribute those price wasn't set yet.
defaultAttributeFee = 0
// defaultNotaryAssistedFee is a default fee for a NotaryAssisted transaction attribute per key.
defaultNotaryAssistedFee = 1000_0000 // 0.1 GAS
// DefaultStoragePrice is the price to pay for 1 byte of storage. // DefaultStoragePrice is the price to pay for 1 byte of storage.
DefaultStoragePrice = 100000 DefaultStoragePrice = 100000
@ -33,9 +39,13 @@ const (
maxFeePerByte = 100_000_000 maxFeePerByte = 100_000_000
// maxStoragePrice is the maximum allowed price for a byte of storage. // maxStoragePrice is the maximum allowed price for a byte of storage.
maxStoragePrice = 10000000 maxStoragePrice = 10000000
// maxAttributeFee is the maximum allowed value for a transaction attribute fee.
maxAttributeFee = 10_00000000
// blockedAccountPrefix is a prefix used to store blocked account. // blockedAccountPrefix is a prefix used to store blocked account.
blockedAccountPrefix = 15 blockedAccountPrefix = 15
// attributeFeePrefix is a prefix used to store attribute fee.
attributeFeePrefix = 20
) )
var ( var (
@ -52,6 +62,9 @@ var (
type Policy struct { type Policy struct {
interop.ContractMD interop.ContractMD
NEO *NEO NEO *NEO
// p2pSigExtensionsEnabled defines whether the P2P signature extensions logic is relevant.
p2pSigExtensionsEnabled bool
} }
type PolicyCache struct { type PolicyCache struct {
@ -59,6 +72,7 @@ type PolicyCache struct {
feePerByte int64 feePerByte int64
maxVerificationGas int64 maxVerificationGas int64
storagePrice uint32 storagePrice uint32
attributeFee map[transaction.AttrType]uint32
blockedAccounts []util.Uint160 blockedAccounts []util.Uint160
} }
@ -76,13 +90,20 @@ func (c *PolicyCache) Copy() dao.NativeContractCache {
func copyPolicyCache(src, dst *PolicyCache) { func copyPolicyCache(src, dst *PolicyCache) {
*dst = *src *dst = *src
dst.attributeFee = make(map[transaction.AttrType]uint32, len(src.attributeFee))
for t, v := range src.attributeFee {
dst.attributeFee[t] = v
}
dst.blockedAccounts = make([]util.Uint160, len(src.blockedAccounts)) dst.blockedAccounts = make([]util.Uint160, len(src.blockedAccounts))
copy(dst.blockedAccounts, src.blockedAccounts) copy(dst.blockedAccounts, src.blockedAccounts)
} }
// newPolicy returns Policy native contract. // newPolicy returns Policy native contract.
func newPolicy() *Policy { func newPolicy(p2pSigExtensionsEnabled bool) *Policy {
p := &Policy{ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID)} p := &Policy{
ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID),
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
}
defer p.UpdateHash() defer p.UpdateHash()
desc := newDescriptor("getFeePerByte", smartcontract.IntegerType) desc := newDescriptor("getFeePerByte", smartcontract.IntegerType)
@ -112,6 +133,17 @@ func newPolicy() *Policy {
md = newMethodAndPrice(p.setStoragePrice, 1<<15, callflag.States) md = newMethodAndPrice(p.setStoragePrice, 1<<15, callflag.States)
p.AddMethod(md, desc) p.AddMethod(md, desc)
desc = newDescriptor("getAttributeFee", smartcontract.IntegerType,
manifest.NewParameter("attributeType", smartcontract.IntegerType))
md = newMethodAndPrice(p.getAttributeFee, 1<<15, callflag.ReadStates)
p.AddMethod(md, desc)
desc = newDescriptor("setAttributeFee", smartcontract.VoidType,
manifest.NewParameter("attributeType", smartcontract.IntegerType),
manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setAttributeFee, 1<<15, callflag.States)
p.AddMethod(md, desc)
desc = newDescriptor("setFeePerByte", smartcontract.VoidType, desc = newDescriptor("setFeePerByte", smartcontract.VoidType,
manifest.NewParameter("value", smartcontract.IntegerType)) manifest.NewParameter("value", smartcontract.IntegerType))
md = newMethodAndPrice(p.setFeePerByte, 1<<15, callflag.States) md = newMethodAndPrice(p.setFeePerByte, 1<<15, callflag.States)
@ -146,8 +178,13 @@ func (p *Policy) Initialize(ic *interop.Context) error {
feePerByte: defaultFeePerByte, feePerByte: defaultFeePerByte,
maxVerificationGas: defaultMaxVerificationGas, maxVerificationGas: defaultMaxVerificationGas,
storagePrice: DefaultStoragePrice, storagePrice: DefaultStoragePrice,
attributeFee: map[transaction.AttrType]uint32{},
blockedAccounts: make([]util.Uint160, 0), blockedAccounts: make([]util.Uint160, 0),
} }
if p.p2pSigExtensionsEnabled {
setIntWithKey(p.ID, ic.DAO, []byte{attributeFeePrefix, byte(transaction.NotaryAssistedT)}, defaultNotaryAssistedFee)
cache.attributeFee[transaction.NotaryAssistedT] = defaultNotaryAssistedFee
}
ic.DAO.SetCache(p.ID, cache) ic.DAO.SetCache(p.ID, cache)
return nil return nil
@ -183,6 +220,25 @@ func (p *Policy) fillCacheFromDAO(cache *PolicyCache, d *dao.Simple) error {
if fErr != nil { if fErr != nil {
return fmt.Errorf("failed to initialize blocked accounts: %w", fErr) return fmt.Errorf("failed to initialize blocked accounts: %w", fErr)
} }
cache.attributeFee = make(map[transaction.AttrType]uint32)
d.Seek(p.ID, storage.SeekRange{Prefix: []byte{attributeFeePrefix}}, func(k, v []byte) bool {
if len(k) != 1 {
fErr = fmt.Errorf("unexpected attribute type len %d (%s)", len(k), hex.EncodeToString(k))
return false
}
t := transaction.AttrType(k[0])
value := bigint.FromBytes(v)
if value == nil {
fErr = fmt.Errorf("unexpected attribute value format: key=%s, value=%s", hex.EncodeToString(k), hex.EncodeToString(v))
return false
}
cache.attributeFee[t] = uint32(value.Int64())
return true
})
if fErr != nil {
return fmt.Errorf("failed to initialize attribute fees: %w", fErr)
}
return nil return nil
} }
@ -297,6 +353,43 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta
return stackitem.Null{} return stackitem.Null{}
} }
func (p *Policy) getAttributeFee(ic *interop.Context, args []stackitem.Item) stackitem.Item {
t := transaction.AttrType(toUint8(args[0]))
if !transaction.IsValidAttrType(ic.Chain.GetConfig().ReservedAttributes, t) {
panic(fmt.Errorf("invalid attribute type: %d", t))
}
return stackitem.NewBigInteger(big.NewInt(p.GetAttributeFeeInternal(ic.DAO, t)))
}
// GetAttributeFeeInternal returns required transaction's attribute fee.
func (p *Policy) GetAttributeFeeInternal(d *dao.Simple, t transaction.AttrType) int64 {
cache := d.GetROCache(p.ID).(*PolicyCache)
v, ok := cache.attributeFee[t]
if !ok {
// We may safely omit this part, but let it be here in case if defaultAttributeFee value is changed.
v = defaultAttributeFee
}
return int64(v)
}
func (p *Policy) setAttributeFee(ic *interop.Context, args []stackitem.Item) stackitem.Item {
t := transaction.AttrType(toUint8(args[0]))
value := toUint32(args[1])
if !transaction.IsValidAttrType(ic.Chain.GetConfig().ReservedAttributes, t) {
panic(fmt.Errorf("invalid attribute type: %d", t))
}
if value > maxAttributeFee {
panic(fmt.Errorf("attribute value is out of range: %d", value))
}
if !p.NEO.checkCommittee(ic) {
panic("invalid committee signature")
}
setIntWithKey(p.ID, ic.DAO, []byte{attributeFeePrefix, byte(t)}, int64(value))
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
cache.attributeFee[t] = value
return stackitem.Null{}
}
// setFeePerByte is a Policy contract method that sets transaction's fee per byte. // setFeePerByte is a Policy contract method that sets transaction's fee per byte.
func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stackitem.Item {
value := toBigInt(args[0]).Int64() value := toBigInt(args[0]).Int64()

View file

@ -21,6 +21,15 @@ const (
NotaryAssistedT AttrType = 0x22 // NotaryAssisted NotaryAssistedT AttrType = 0x22 // NotaryAssisted
) )
// attrTypes contains a set of valid attribute types (does not include reserved attributes).
var attrTypes = map[AttrType]struct{}{
HighPriority: {},
OracleResponseT: {},
NotValidBeforeT: {},
ConflictsT: {},
NotaryAssistedT: {},
}
func (a AttrType) allowMultiple() bool { func (a AttrType) allowMultiple() bool {
switch a { switch a {
case ConflictsT: case ConflictsT:
@ -29,3 +38,11 @@ func (a AttrType) allowMultiple() bool {
return false return false
} }
} }
// IsValidAttrType returns whether the provided attribute type is valid.
func IsValidAttrType(reservedAttributesEnabled bool, attrType AttrType) bool {
if _, ok := attrTypes[attrType]; ok {
return true
}
return reservedAttributesEnabled && ReservedLowerBound <= attrType && attrType <= ReservedUpperBound
}

View file

@ -45,13 +45,3 @@ func GetMaxNotValidBeforeDelta() int {
func SetMaxNotValidBeforeDelta(value int) { func SetMaxNotValidBeforeDelta(value int) {
neogointernal.CallWithTokenNoRet(Hash, "setMaxNotValidBeforeDelta", int(contract.States), value) neogointernal.CallWithTokenNoRet(Hash, "setMaxNotValidBeforeDelta", int(contract.States), value)
} }
// GetNotaryServiceFeePerKey represents `getNotaryServiceFeePerKey` method of Notary native contract.
func GetNotaryServiceFeePerKey() int {
return neogointernal.CallWithToken(Hash, "getNotaryServiceFeePerKey", int(contract.ReadStates)).(int)
}
// SetNotaryServiceFeePerKey represents `setNotaryServiceFeePerKey` method of Notary native contract.
func SetNotaryServiceFeePerKey(value int) {
neogointernal.CallWithTokenNoRet(Hash, "setNotaryServiceFeePerKey", int(contract.States), value)
}

View file

@ -0,0 +1,14 @@
package policy
// AttributeType represents a transaction attribute type.
type AttributeType byte
// List of valid transaction attribute types.
const (
HighPriorityT AttributeType = 1
OracleResponseT AttributeType = 0x11
NotValidBeforeT AttributeType = 0x20
ConflictsT AttributeType = 0x21
// NotaryAssistedT is an extension of Neo protocol available on specifically configured NeoGo networks.
NotaryAssistedT AttributeType = 0x22
)

View file

@ -43,6 +43,16 @@ func SetStoragePrice(value int) {
neogointernal.CallWithTokenNoRet(Hash, "setStoragePrice", int(contract.States), value) neogointernal.CallWithTokenNoRet(Hash, "setStoragePrice", int(contract.States), value)
} }
// GetAttributeFee represents `getAttributeFee` method of Policy native contract.
func GetAttributeFee(t AttributeType) int {
return neogointernal.CallWithToken(Hash, "getAttributeFee", int(contract.ReadStates), t).(int)
}
// SetAttributeFee represents `setAttributeFee` method of Policy native contract.
func SetAttributeFee(t AttributeType, value int) {
neogointernal.CallWithTokenNoRet(Hash, "setAttributeFee", int(contract.States), t, value)
}
// IsBlocked represents `isBlocked` method of Policy native contract. // IsBlocked represents `isBlocked` method of Policy native contract.
func IsBlocked(addr interop.Hash160) bool { func IsBlocked(addr interop.Hash160) bool {
return neogointernal.CallWithToken(Hash, "isBlocked", int(contract.ReadStates), addr).(bool) return neogointernal.CallWithToken(Hash, "isBlocked", int(contract.ReadStates), addr).(bool)

View file

@ -305,7 +305,7 @@ func AddNetworkFee(bc *core.Blockchain, tx *transaction.Transaction, signers ...
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
} }
tx.NetworkFee += int64(size) * bc.FeePerByte() tx.NetworkFee += int64(size)*bc.FeePerByte() + bc.CalculateAttributesFee(tx)
} }
// NewUnsignedBlock creates a new unsigned block from txs. // NewUnsignedBlock creates a new unsigned block from txs.

View file

@ -111,12 +111,6 @@ func (c *ContractReader) GetMaxNotValidBeforeDelta() (uint32, error) {
return uint32(ret), err return uint32(ret), err
} }
// GetNotaryServiceFeePerKey returns the per-key fee amount paid by transactions
// for the NotaryAssisted attribute.
func (c *ContractReader) GetNotaryServiceFeePerKey() (int64, error) {
return unwrap.Int64(c.invoker.Call(Hash, "getNotaryServiceFeePerKey"))
}
// LockDepositUntil creates and sends a transaction that extends the deposit lock // LockDepositUntil creates and sends a transaction that extends the deposit lock
// time for the given account. The return result from the "lockDepositUntil" // time for the given account. The return result from the "lockDepositUntil"
// method is checked to be true, so transaction fails (with FAULT state) if not // method is checked to be true, so transaction fails (with FAULT state) if not
@ -182,33 +176,6 @@ func (c *Contract) SetMaxNotValidBeforeDeltaUnsigned(blocks uint32) (*transactio
return c.actor.MakeUnsignedCall(Hash, setMaxNVBDeltaMethod, nil, blocks) return c.actor.MakeUnsignedCall(Hash, setMaxNVBDeltaMethod, nil, blocks)
} }
// SetNotaryServiceFeePerKey creates and sends a transaction that sets the new
// per-key fee value paid for using the notary service. The action is successful
// when transaction ends in HALT state. Notice that this setting can be changed
// only by the network's committee, so use an appropriate Actor. The returned
// values are transaction hash, its ValidUntilBlock value and an error if any.
func (c *Contract) SetNotaryServiceFeePerKey(fee int64) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, setFeePKMethod, fee)
}
// SetNotaryServiceFeePerKeyTransaction creates a transaction that sets the new
// per-key fee value paid for using the notary service. The action is successful
// when transaction ends in HALT state. Notice that this setting can be changed
// only by the network's committee, so use an appropriate Actor. The transaction
// is signed, but not sent to the network, instead it's returned to the caller.
func (c *Contract) SetNotaryServiceFeePerKeyTransaction(fee int64) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, setFeePKMethod, fee)
}
// SetNotaryServiceFeePerKeyUnsigned creates a transaction that sets the new
// per-key fee value paid for using the notary service. The action is successful
// when transaction ends in HALT state. Notice that this setting can be changed
// only by the network's committee, so use an appropriate Actor. The transaction
// is not signed and just returned to the caller.
func (c *Contract) SetNotaryServiceFeePerKeyUnsigned(fee int64) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, setFeePKMethod, nil, fee)
}
// Withdraw creates and sends a transaction that withdraws the deposit belonging // Withdraw creates and sends a transaction that withdraws the deposit belonging
// to "from" account and sends it to "to" account. The return result from the // to "from" account and sends it to "to" account. The return result from the
// "withdraw" method is checked to be true, so transaction fails (with FAULT // "withdraw" method is checked to be true, so transaction fails (with FAULT

View file

@ -103,26 +103,6 @@ func TestUint32Getters(t *testing.T) {
} }
} }
func TestGetNotaryServiceFeePerKey(t *testing.T) {
ta := &testAct{}
ntr := NewReader(ta)
ta.err = errors.New("")
_, err := ntr.GetNotaryServiceFeePerKey()
require.Error(t, err)
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make(42),
},
}
res, err := ntr.GetNotaryServiceFeePerKey()
require.NoError(t, err)
require.Equal(t, int64(42), res)
}
func TestTxSenders(t *testing.T) { func TestTxSenders(t *testing.T) {
ta := new(testAct) ta := new(testAct)
ntr := New(ta) ntr := New(ta)
@ -134,9 +114,6 @@ func TestTxSenders(t *testing.T) {
"SetMaxNotValidBeforeDelta": func() (util.Uint256, uint32, error) { "SetMaxNotValidBeforeDelta": func() (util.Uint256, uint32, error) {
return ntr.SetMaxNotValidBeforeDelta(42) return ntr.SetMaxNotValidBeforeDelta(42)
}, },
"SetNotaryServiceFeePerKey": func() (util.Uint256, uint32, error) {
return ntr.SetNotaryServiceFeePerKey(100500)
},
"Withdraw": func() (util.Uint256, uint32, error) { "Withdraw": func() (util.Uint256, uint32, error) {
return ntr.Withdraw(util.Uint160{1, 2, 3}, util.Uint160{3, 2, 1}) return ntr.Withdraw(util.Uint160{1, 2, 3}, util.Uint160{3, 2, 1})
}, },
@ -174,12 +151,6 @@ func TestTxMakers(t *testing.T) {
"SetMaxNotValidBeforeDeltaUnsigned": func() (*transaction.Transaction, error) { "SetMaxNotValidBeforeDeltaUnsigned": func() (*transaction.Transaction, error) {
return ntr.SetMaxNotValidBeforeDeltaUnsigned(42) return ntr.SetMaxNotValidBeforeDeltaUnsigned(42)
}, },
"SetNotaryServiceFeePerKeyTransaction": func() (*transaction.Transaction, error) {
return ntr.SetNotaryServiceFeePerKeyTransaction(100500)
},
"SetNotaryServiceFeePerKeyUnsigned": func() (*transaction.Transaction, error) {
return ntr.SetNotaryServiceFeePerKeyUnsigned(100500)
},
"WithdrawTransaction": func() (*transaction.Transaction, error) { "WithdrawTransaction": func() (*transaction.Transaction, error) {
return ntr.WithdrawTransaction(util.Uint160{1, 2, 3}, util.Uint160{3, 2, 1}) return ntr.WithdrawTransaction(util.Uint160{1, 2, 3}, util.Uint160{3, 2, 1})
}, },

View file

@ -40,6 +40,7 @@ const (
execFeeSetter = "setExecFeeFactor" execFeeSetter = "setExecFeeFactor"
feePerByteSetter = "setFeePerByte" feePerByteSetter = "setFeePerByte"
storagePriceSetter = "setStoragePrice" storagePriceSetter = "setStoragePrice"
attributeFeeSetter = "setAttributeFee"
) )
// ContractReader provides an interface to call read-only PolicyContract // ContractReader provides an interface to call read-only PolicyContract
@ -88,6 +89,12 @@ func (c *ContractReader) GetStoragePrice() (int64, error) {
return unwrap.Int64(c.invoker.Call(Hash, "getStoragePrice")) return unwrap.Int64(c.invoker.Call(Hash, "getStoragePrice"))
} }
// GetAttributeFee returns current fee for the specified attribute usage. Any
// contract saving data to the storage pays for it according to this value.
func (c *ContractReader) GetAttributeFee(t transaction.AttrType) (int64, error) {
return unwrap.Int64(c.invoker.Call(Hash, "getAttributeFee", byte(t)))
}
// IsBlocked checks if the given account is blocked in the PolicyContract. // IsBlocked checks if the given account is blocked in the PolicyContract.
func (c *ContractReader) IsBlocked(account util.Uint160) (bool, error) { func (c *ContractReader) IsBlocked(account util.Uint160) (bool, error) {
return unwrap.Bool(c.invoker.Call(Hash, "isBlocked", account)) return unwrap.Bool(c.invoker.Call(Hash, "isBlocked", account))
@ -158,6 +165,28 @@ func (c *Contract) SetStoragePriceUnsigned(value int64) (*transaction.Transactio
return c.actor.MakeUnsignedCall(Hash, storagePriceSetter, nil, value) return c.actor.MakeUnsignedCall(Hash, storagePriceSetter, nil, value)
} }
// SetAttributeFee creates and sends a transaction that sets the new attribute
// fee value for the specified attribute. The action is successful when
// transaction ends in HALT state. The returned values are transaction hash, its
// ValidUntilBlock value and an error if any.
func (c *Contract) SetAttributeFee(t transaction.AttrType, value int64) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, attributeFeeSetter, byte(t), value)
}
// SetAttributeFeeTransaction creates a transaction that sets the new attribute
// fee value for the specified attribute. This transaction is signed, but not
// sent to the network, instead it's returned to the caller.
func (c *Contract) SetAttributeFeeTransaction(t transaction.AttrType, value int64) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, attributeFeeSetter, byte(t), value)
}
// SetAttributeFeeUnsigned creates a transaction that sets the new attribute fee
// value for the specified attribute. This transaction is not signed and just
// returned to the caller.
func (c *Contract) SetAttributeFeeUnsigned(t transaction.AttrType, value int64) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, attributeFeeSetter, nil, byte(t), value)
}
// BlockAccount creates and sends a transaction that blocks an account on the // BlockAccount creates and sends a transaction that blocks an account on the
// network (via `blockAccount` method), it fails (with FAULT state) if it's not // network (via `blockAccount` method), it fails (with FAULT state) if it's not
// successful. The returned values are transaction hash, its // successful. The returned values are transaction hash, its

View file

@ -58,6 +58,8 @@ func TestReader(t *testing.T) {
} }
_, err := pc.IsBlocked(util.Uint160{1, 2, 3}) _, err := pc.IsBlocked(util.Uint160{1, 2, 3})
require.Error(t, err) require.Error(t, err)
_, err = pc.GetAttributeFee(transaction.ConflictsT)
require.Error(t, err)
ta.err = nil ta.err = nil
ta.res = &result.Invoke{ ta.res = &result.Invoke{
@ -71,6 +73,9 @@ func TestReader(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, int64(42), val) require.Equal(t, int64(42), val)
} }
v, err := pc.GetAttributeFee(transaction.ConflictsT)
require.NoError(t, err)
require.Equal(t, int64(42), v)
ta.res = &result.Invoke{ ta.res = &result.Invoke{
State: "HALT", State: "HALT",
Stack: []stackitem.Item{ Stack: []stackitem.Item{
@ -97,6 +102,8 @@ func TestIntSetters(t *testing.T) {
_, _, err := m(42) _, _, err := m(42)
require.Error(t, err) require.Error(t, err)
} }
_, _, err := pc.SetAttributeFee(transaction.OracleResponseT, 123)
require.Error(t, err)
ta.err = nil ta.err = nil
ta.txh = util.Uint256{1, 2, 3} ta.txh = util.Uint256{1, 2, 3}
@ -107,6 +114,10 @@ func TestIntSetters(t *testing.T) {
require.Equal(t, ta.txh, h) require.Equal(t, ta.txh, h)
require.Equal(t, ta.vub, vub) require.Equal(t, ta.vub, vub)
} }
h, vub, err := pc.SetAttributeFee(transaction.OracleResponseT, 123)
require.NoError(t, err)
require.Equal(t, ta.txh, h)
require.Equal(t, ta.vub, vub)
} }
func TestUint160Setters(t *testing.T) { func TestUint160Setters(t *testing.T) {

View file

@ -183,6 +183,10 @@ func TestClientPolicyContract(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, int64(100000), val) require.Equal(t, int64(100000), val)
val, err = polizei.GetAttributeFee(transaction.NotaryAssistedT)
require.NoError(t, err)
require.Equal(t, int64(1000_0000), val)
ret, err := polizei.IsBlocked(util.Uint160{}) ret, err := polizei.IsBlocked(util.Uint160{})
require.NoError(t, err) require.NoError(t, err)
require.False(t, ret) require.False(t, ret)
@ -212,14 +216,17 @@ func TestClientPolicyContract(t *testing.T) {
txstorage, err := polis.SetStoragePriceUnsigned(100500) txstorage, err := polis.SetStoragePriceUnsigned(100500)
require.NoError(t, err) require.NoError(t, err)
txattr, err := polis.SetAttributeFeeUnsigned(transaction.NotaryAssistedT, 100500)
require.NoError(t, err)
txblock, err := polis.BlockAccountUnsigned(util.Uint160{1, 2, 3}) txblock, err := polis.BlockAccountUnsigned(util.Uint160{1, 2, 3})
require.NoError(t, err) require.NoError(t, err)
for _, tx := range []*transaction.Transaction{txblock, txstorage, txnetfee, txexec} { for _, tx := range []*transaction.Transaction{txattr, txblock, txstorage, txnetfee, txexec} {
tx.Scripts[0].InvocationScript = testchain.SignCommittee(tx) tx.Scripts[0].InvocationScript = testchain.SignCommittee(tx)
} }
bl := testchain.NewBlock(t, chain, 1, 0, txblock, txstorage, txnetfee, txexec) bl := testchain.NewBlock(t, chain, 1, 0, txattr, txblock, txstorage, txnetfee, txexec)
_, err = c.SubmitBlock(*bl) _, err = c.SubmitBlock(*bl)
require.NoError(t, err) require.NoError(t, err)
@ -235,6 +242,10 @@ func TestClientPolicyContract(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, int64(100500), val) require.Equal(t, int64(100500), val)
val, err = polizei.GetAttributeFee(transaction.NotaryAssistedT)
require.NoError(t, err)
require.Equal(t, int64(100500), val)
ret, err = polizei.IsBlocked(util.Uint160{1, 2, 3}) ret, err = polizei.IsBlocked(util.Uint160{1, 2, 3})
require.NoError(t, err) require.NoError(t, err)
require.True(t, ret) require.True(t, ret)
@ -480,10 +491,6 @@ func TestClientNotary(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, uint32(140), maxNVBd) require.Equal(t, uint32(140), maxNVBd)
feePerKey, err := notaReader.GetNotaryServiceFeePerKey()
require.NoError(t, err)
require.Equal(t, int64(1000_0000), feePerKey)
commAct, err := actor.New(c, []actor.SignerAccount{{ commAct, err := actor.New(c, []actor.SignerAccount{{
Signer: transaction.Signer{ Signer: transaction.Signer{
Account: testchain.CommitteeScriptHash(), Account: testchain.CommitteeScriptHash(),
@ -501,12 +508,9 @@ func TestClientNotary(t *testing.T) {
txNVB, err := notaComm.SetMaxNotValidBeforeDeltaUnsigned(210) txNVB, err := notaComm.SetMaxNotValidBeforeDeltaUnsigned(210)
require.NoError(t, err) require.NoError(t, err)
txFee, err := notaComm.SetNotaryServiceFeePerKeyUnsigned(500_0000)
require.NoError(t, err)
txNVB.Scripts[0].InvocationScript = testchain.SignCommittee(txNVB) txNVB.Scripts[0].InvocationScript = testchain.SignCommittee(txNVB)
txFee.Scripts[0].InvocationScript = testchain.SignCommittee(txFee) bl := testchain.NewBlock(t, chain, 1, 0, txNVB)
bl := testchain.NewBlock(t, chain, 1, 0, txNVB, txFee)
_, err = c.SubmitBlock(*bl) _, err = c.SubmitBlock(*bl)
require.NoError(t, err) require.NoError(t, err)
@ -514,10 +518,6 @@ func TestClientNotary(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, uint32(210), maxNVBd) require.Equal(t, uint32(210), maxNVBd)
feePerKey, err = notaReader.GetNotaryServiceFeePerKey()
require.NoError(t, err)
require.Equal(t, int64(500_0000), feePerKey)
privAct, err := actor.New(c, []actor.SignerAccount{{ privAct, err := actor.New(c, []actor.SignerAccount{{
Signer: transaction.Signer{ Signer: transaction.Signer{
Account: priv0Hash, Account: priv0Hash,
@ -743,12 +743,13 @@ func TestCalculateNetworkFee(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, c.Init()) require.NoError(t, c.Init())
h, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
require.NoError(t, err)
priv := testchain.PrivateKeyByID(0)
acc0 := wallet.NewAccountFromPrivateKey(priv)
t.Run("ContractWithArgs", func(t *testing.T) { t.Run("ContractWithArgs", func(t *testing.T) {
check := func(t *testing.T, extraFee int64) { check := func(t *testing.T, extraFee int64) {
h, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
require.NoError(t, err)
priv := testchain.PrivateKeyByID(0)
acc0 := wallet.NewAccountFromPrivateKey(priv)
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0) tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
require.NoError(t, err) require.NoError(t, err)
tx.ValidUntilBlock = chain.BlockHeight() + 10 tx.ValidUntilBlock = chain.BlockHeight() + 10
@ -802,6 +803,62 @@ func TestCalculateNetworkFee(t *testing.T) {
check(t, -1) check(t, -1)
}) })
}) })
t.Run("extra attribute fee", func(t *testing.T) {
const conflictsFee = 100
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
tx.ValidUntilBlock = chain.BlockHeight() + 10
signer0 := transaction.Signer{
Account: acc0.ScriptHash(),
Scopes: transaction.CalledByEntry,
}
priv1 := testchain.PrivateKeyByID(1)
acc1 := wallet.NewAccountFromPrivateKey(priv1)
signer1 := transaction.Signer{
Account: acc1.ScriptHash(),
Scopes: transaction.CalledByEntry,
}
tx.Signers = []transaction.Signer{signer0, signer1}
tx.Attributes = []transaction.Attribute{
{
Type: transaction.ConflictsT,
Value: &transaction.Conflicts{Hash: util.Uint256{1, 2, 3}},
},
}
tx.Scripts = []transaction.Witness{
{VerificationScript: acc0.Contract.Script},
{VerificationScript: acc1.Contract.Script},
}
oldFee, err := c.CalculateNetworkFee(tx)
require.NoError(t, err)
// Set fee per Conflicts attribute.
script, err := smartcontract.CreateCallScript(state.CreateNativeContractHash(nativenames.Policy), "setAttributeFee", byte(transaction.ConflictsT), conflictsFee)
require.NoError(t, err)
txSetFee := transaction.New(script, 1_0000_0000)
txSetFee.ValidUntilBlock = chain.BlockHeight() + 1
txSetFee.Signers = []transaction.Signer{
signer0,
{
Account: testchain.CommitteeScriptHash(),
Scopes: transaction.CalledByEntry,
},
}
txSetFee.NetworkFee = 10_0000_0000
require.NoError(t, acc0.SignTx(testchain.Network(), txSetFee))
txSetFee.Scripts = append(txSetFee.Scripts, transaction.Witness{
InvocationScript: testchain.SignCommittee(txSetFee),
VerificationScript: testchain.CommitteeVerificationScript(),
})
require.NoError(t, chain.AddBlock(testchain.NewBlock(t, chain, 1, 0, txSetFee)))
// Calculate network fee one more time with updated Conflicts price.
newFee, err := c.CalculateNetworkFee(tx)
require.NoError(t, err)
expectedDiff := len(tx.Signers) * len(tx.GetAttributes(transaction.ConflictsT)) * conflictsFee
require.Equal(t, int64(expectedDiff), newFee-oldFee)
})
} }
func TestNotaryActor(t *testing.T) { func TestNotaryActor(t *testing.T) {

View file

@ -65,6 +65,7 @@ type (
Ledger interface { Ledger interface {
AddBlock(block *block.Block) error AddBlock(block *block.Block) error
BlockHeight() uint32 BlockHeight() uint32
CalculateAttributesFee(tx *transaction.Transaction) int64
CalculateClaimable(h util.Uint160, endHeight uint32) (*big.Int, error) CalculateClaimable(h util.Uint160, endHeight uint32) (*big.Int, error)
CurrentBlockHash() util.Uint256 CurrentBlockHash() util.Uint256
FeePerByte() int64 FeePerByte() int64
@ -89,7 +90,6 @@ type (
GetNatives() []state.NativeContract GetNatives() []state.NativeContract
GetNextBlockValidators() ([]*keys.PublicKey, error) GetNextBlockValidators() ([]*keys.PublicKey, error)
GetNotaryContractScriptHash() util.Uint160 GetNotaryContractScriptHash() util.Uint160
GetNotaryServiceFeePerKey() int64
GetStateModule() core.StateRoot GetStateModule() core.StateRoot
GetStorageItem(id int32, key []byte) state.StorageItem GetStorageItem(id int32, key []byte) state.StorageItem
GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, nextBlockHeight uint32) (*interop.Context, error) GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, nextBlockHeight uint32) (*interop.Context, error)
@ -975,15 +975,7 @@ func (s *Server) calculateNetworkFee(reqParams params.Params) (any, *neorpc.Erro
netFee += gasConsumed netFee += gasConsumed
size += io.GetVarSize(w.VerificationScript) + io.GetVarSize(w.InvocationScript) size += io.GetVarSize(w.VerificationScript) + io.GetVarSize(w.InvocationScript)
} }
if s.chain.P2PSigExtensionsEnabled() { netFee += int64(size)*s.chain.FeePerByte() + s.chain.CalculateAttributesFee(tx)
attrs := tx.GetAttributes(transaction.NotaryAssistedT)
if len(attrs) != 0 {
na := attrs[0].Value.(*transaction.NotaryAssisted)
netFee += (int64(na.NKeys) + 1) * s.chain.GetNotaryServiceFeePerKey()
}
}
fee := s.chain.FeePerByte()
netFee += int64(size) * fee
return result.NetworkFee{Value: netFee}, nil return result.NetworkFee{Value: netFee}, nil
} }

View file

@ -138,7 +138,7 @@ func initClearServerWithCustomConfig(t testing.TB, ccfg func(configuration *conf
} }
func initClearServerWithInMemoryChain(t testing.TB) (*core.Blockchain, *Server, *httptest.Server) { func initClearServerWithInMemoryChain(t testing.TB) (*core.Blockchain, *Server, *httptest.Server) {
return initClearServerWithServices(t, false, false, false) return initClearServerWithServices(t, false, true, false)
} }
func initServerWithInMemoryChain(t *testing.T) (*core.Blockchain, *Server, *httptest.Server) { func initServerWithInMemoryChain(t *testing.T) (*core.Blockchain, *Server, *httptest.Server) {

View file

@ -87,7 +87,7 @@ const (
faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60" faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60"
faultedTxBlock uint32 = 23 faultedTxBlock uint32 = 23
invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA" invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA"
block20StateRootLE = "cc8315751c5b6edf39c14f1637bfa0595d6ca86b8ed4d41cb495d572b680504f" block20StateRootLE = "858c873539d6d24a70f2be13f9dafc61aef2b63c2aa16bb440676de6e44e3cf1"
) )
var ( var (