diff --git a/ROADMAP.md b/ROADMAP.md index 9c8247e0d..0db81766f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -57,4 +57,4 @@ NeoGo retains certain deprecated error codes: `neorpc.ErrCompatGeneric`, `neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the 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. \ No newline at end of file +Removal of the deprecated RPC error codes is planned once all nodes adopt the new error standard. diff --git a/examples/engine/go.mod b/examples/engine/go.mod index 7e25f531a..005e37a4e 100644 --- a/examples/engine/go.mod +++ b/examples/engine/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine go 1.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 diff --git a/examples/engine/go.sum b/examples/engine/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/engine/go.sum +++ b/examples/engine/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/events/go.mod b/examples/events/go.mod index 4b94da500..27b9762c2 100644 --- a/examples/events/go.mod +++ b/examples/events/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events go 1.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 diff --git a/examples/events/go.sum b/examples/events/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/events/go.sum +++ b/examples/events/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/iterator/go.mod b/examples/iterator/go.mod index 8b92cdb4d..f7ca449c6 100644 --- a/examples/iterator/go.mod +++ b/examples/iterator/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator go 1.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 diff --git a/examples/iterator/go.sum b/examples/iterator/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/iterator/go.sum +++ b/examples/iterator/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/nft-d/go.mod b/examples/nft-d/go.mod index 334832330..0c72cdfe8 100644 --- a/examples/nft-d/go.mod +++ b/examples/nft-d/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft go 1.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 diff --git a/examples/nft-d/go.sum b/examples/nft-d/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/nft-d/go.sum +++ b/examples/nft-d/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/nft-nd-nns/go.mod b/examples/nft-nd-nns/go.mod index c122dfecc..e0c089e42 100644 --- a/examples/nft-nd-nns/go.mod +++ b/examples/nft-nd-nns/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( 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 ) diff --git a/examples/nft-nd-nns/go.sum b/examples/nft-nd-nns/go.sum index 4182ad12a..48602a435 100644 --- a/examples/nft-nd-nns/go.sum +++ b/examples/nft-nd-nns/go.sum @@ -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/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/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +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-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= diff --git a/examples/nft-nd/go.mod b/examples/nft-nd/go.mod index ebf84e374..3fe76bdd3 100644 --- a/examples/nft-nd/go.mod +++ b/examples/nft-nd/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd go 1.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 diff --git a/examples/nft-nd/go.sum b/examples/nft-nd/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/nft-nd/go.sum +++ b/examples/nft-nd/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/oracle/go.mod b/examples/oracle/go.mod index 133a0193c..6faef11c0 100644 --- a/examples/oracle/go.mod +++ b/examples/oracle/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle go 1.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 diff --git a/examples/oracle/go.sum b/examples/oracle/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/oracle/go.sum +++ b/examples/oracle/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/runtime/go.mod b/examples/runtime/go.mod index ce77c462f..8cb23c44c 100644 --- a/examples/runtime/go.mod +++ b/examples/runtime/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime go 1.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 diff --git a/examples/runtime/go.sum b/examples/runtime/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/runtime/go.sum +++ b/examples/runtime/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/storage/go.mod b/examples/storage/go.mod index 48900d491..f62e1dad4 100644 --- a/examples/storage/go.mod +++ b/examples/storage/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage go 1.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 diff --git a/examples/storage/go.sum b/examples/storage/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/storage/go.sum +++ b/examples/storage/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/timer/go.mod b/examples/timer/go.mod index c514153d8..38233f015 100644 --- a/examples/timer/go.mod +++ b/examples/timer/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer go 1.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 diff --git a/examples/timer/go.sum b/examples/timer/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/timer/go.sum +++ b/examples/timer/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/token/go.mod b/examples/token/go.mod index bc3008f56..ebc391f31 100644 --- a/examples/token/go.mod +++ b/examples/token/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token go 1.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 diff --git a/examples/token/go.sum b/examples/token/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/token/go.sum +++ b/examples/token/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/examples/zkp/cubic_circuit/go.sum b/examples/zkp/cubic_circuit/go.sum index ecef282f5..f64ffbf93 100644 --- a/examples/zkp/cubic_circuit/go.sum +++ b/examples/zkp/cubic_circuit/go.sum @@ -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/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= 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-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= diff --git a/examples/zkp/xor_compat/go.mod b/examples/zkp/xor_compat/go.mod index f2bb1f4b8..28b1911d6 100644 --- a/examples/zkp/xor_compat/go.mod +++ b/examples/zkp/xor_compat/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor 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 diff --git a/examples/zkp/xor_compat/go.sum b/examples/zkp/xor_compat/go.sum index a5cf078ec..080fa5463 100644 --- a/examples/zkp/xor_compat/go.sum +++ b/examples/zkp/xor_compat/go.sum @@ -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-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= +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-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/go.mod b/go.mod index 6867a9bc8..c7d3414fc 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/mr-tron/base58 v1.2.0 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/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/rfc6979 v0.2.0 github.com/pierrec/lz4 v2.6.1+incompatible diff --git a/go.sum b/go.sum index 59843eae8..178271451 100644 --- a/go.sum +++ b/go.sum @@ -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/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231120162333-406c9f8b9214 h1:v8XJTwSAAF4Wwp20yfW8Ihz6BBPXBOGmLloWVa5EuSM= -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 h1:hPVF8iMmsQ15GSemj1ma6C9BkwfAugEXsUAVTEniK5M= +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/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= diff --git a/internal/contracts/oracle_contract/go.mod b/internal/contracts/oracle_contract/go.mod index 05e56d860..03761e503 100644 --- a/internal/contracts/oracle_contract/go.mod +++ b/internal/contracts/oracle_contract/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle 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 diff --git a/internal/contracts/oracle_contract/go.sum b/internal/contracts/oracle_contract/go.sum index a5cf078ec..080fa5463 100644 --- a/internal/contracts/oracle_contract/go.sum +++ b/internal/contracts/oracle_contract/go.sum @@ -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-20231120162333-406c9f8b9214/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= +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-20231121104256-0493ddbd70b2/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag= diff --git a/internal/testchain/transaction.go b/internal/testchain/transaction.go index 43b817d98..1b33db59c 100644 --- a/internal/testchain/transaction.go +++ b/internal/testchain/transaction.go @@ -25,6 +25,7 @@ import ( // Ledger is an interface that abstracts the implementation of the blockchain. type Ledger interface { BlockHeight() uint32 + CalculateAttributesFee(tx *transaction.Transaction) int64 FeePerByte() int64 GetBaseExecFee() int64 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) tx.NetworkFee += netFee size += sizeDelta - tx.NetworkFee += int64(size) * bc.FeePerByte() + tx.NetworkFee += int64(size)*bc.FeePerByte() + bc.CalculateAttributesFee(tx) tx.Scripts = []transaction.Witness{{ InvocationScript: sign(tx), VerificationScript: verif, diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go index 8f3b8487b..8daf8b6b4 100644 --- a/pkg/compiler/native_test.go +++ b/pkg/compiler/native_test.go @@ -123,6 +123,14 @@ func TestLedgerVMStates(t *testing.T) { 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 { method string params []string @@ -179,6 +187,8 @@ func TestNativeHelpersCompile(t *testing.T) { {"setFeePerByte", []string{"42"}}, {"setStoragePrice", []string{"42"}}, {"unblockAccount", []string{u160}}, + {"getAttributeFee", []string{"1"}}, + {"setAttributeFee", []string{"1", "123"}}, }) runNativeTestCases(t, cs.Ledger.ContractMD, "ledger", []nativeTestCase{ {"currentHash", nil}, @@ -197,8 +207,6 @@ func TestNativeHelpersCompile(t *testing.T) { {"expirationOf", []string{u160}}, {"getMaxNotValidBeforeDelta", nil}, {"setMaxNotValidBeforeDelta", []string{"42"}}, - {"getNotaryServiceFeePerKey", nil}, - {"setNotaryServiceFeePerKey", []string{"42"}}, }) runNativeTestCases(t, cs.Management.ContractMD, "management", []nativeTestCase{ {"deploy", []string{"nil", "nil"}}, diff --git a/pkg/consensus/consensus.go b/pkg/consensus/consensus.go index 59e775125..908683705 100644 --- a/pkg/consensus/consensus.go +++ b/pkg/consensus/consensus.go @@ -53,6 +53,7 @@ type Ledger interface { SubscribeForBlocks(ch chan *coreb.Block) UnsubscribeFromBlocks(ch chan *coreb.Block) GetBaseExecFee() int64 + CalculateAttributesFee(tx *transaction.Transaction) int64 interop.Ledger mempool.Feer } diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index 07eeb99ed..c095e8e3e 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -592,7 +592,7 @@ func signTx(t *testing.T, bc Ledger, txs ...*transaction.Transaction) { netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript) tx.NetworkFee += +netFee size += sizeDelta - tx.NetworkFee += int64(size) * bc.FeePerByte() + tx.NetworkFee += int64(size)*bc.FeePerByte() + bc.CalculateAttributesFee(tx) buf := io.NewBufBinWriter() for _, key := range privNetKeys { diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 5882da12a..fab0c5f51 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -2054,10 +2054,10 @@ func (bc *Blockchain) GetNotaryBalance(acc util.Uint160) *big.Int { return bc.contracts.Notary.BalanceOf(bc.dao, acc) } -// GetNotaryServiceFeePerKey returns NotaryServiceFeePerKey which is a reward per -// notary request key for designated notary nodes. +// GetNotaryServiceFeePerKey returns a NotaryAssisted transaction attribute fee +// per key which is a reward per notary request key for designated notary nodes. 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. @@ -2479,14 +2479,7 @@ func (bc *Blockchain) verifyAndPoolTx(t *transaction.Transaction, pool *mempool. if size > transaction.MaxTransactionSize { return fmt.Errorf("%w: (%d > MaxTransactionSize %d)", ErrTxTooBig, size, transaction.MaxTransactionSize) } - needNetworkFee := int64(size) * bc.FeePerByte() - 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) - } - } + needNetworkFee := int64(size)*bc.FeePerByte() + bc.CalculateAttributesFee(t) netFee := t.NetworkFee - needNetworkFee if netFee < 0 { 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 } } - err = bc.verifyTxWitnesses(t, nil, isPartialTx) + err = bc.verifyTxWitnesses(t, nil, isPartialTx, netFee) if err != nil { return err } @@ -2530,6 +2523,27 @@ func (bc *Blockchain) verifyAndPoolTx(t *transaction.Transaction, pool *mempool. 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 { for i := range tx.Attributes { 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 // 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 -// 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). -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) - gasLimit := t.NetworkFee - int64(t.Size())*bc.FeePerByte() - if bc.P2PSigExtensionsEnabled() { - attrs := t.GetAttributes(transaction.NotaryAssistedT) - if len(attrs) != 0 { - na := attrs[0].Value.(*transaction.NotaryAssisted) - gasLimit -= (int64(na.NKeys) + 1) * bc.contracts.Notary.GetNotaryServiceFeePerKey(bc.dao) - } + var gasLimit int64 + if len(verificationFee) == 0 { + gasLimit = t.NetworkFee - int64(t.Size())*bc.FeePerByte() - bc.CalculateAttributesFee(t) + } else { + gasLimit = verificationFee[0] } for i := range t.Signers { gasConsumed, err := bc.verifyHashAgainstScript(t.Signers[i].Account, &t.Scripts[i], interopCtx, gasLimit) diff --git a/pkg/core/native/contract.go b/pkg/core/native/contract.go index 19321f887..4b9dc1b4c 100644 --- a/pkg/core/native/contract.go +++ b/pkg/core/native/contract.go @@ -74,10 +74,11 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts { gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions) neo := newNEO(cfg) - policy := newPolicy() + policy := newPolicy(cfg.P2PSigExtensions) neo.GAS = gas neo.Policy = policy gas.NEO = neo + gas.Policy = policy mgmt.NEO = neo mgmt.Policy = policy policy.NEO = neo @@ -104,8 +105,8 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts { notary.GAS = gas notary.NEO = neo notary.Desig = desig + notary.Policy = policy cs.Notary = notary - gas.Notary = notary cs.Contracts = append(cs.Contracts, notary) } diff --git a/pkg/core/native/management_test.go b/pkg/core/native/management_test.go index 421899f24..4184eb593 100644 --- a/pkg/core/native/management_test.go +++ b/pkg/core/native/management_test.go @@ -17,7 +17,7 @@ import ( func TestDeployGetUpdateDestroyContract(t *testing.T) { mgmt := newManagement() - mgmt.Policy = newPolicy() + mgmt.Policy = newPolicy(false) d := dao.NewSimple(storage.NewMemoryStore(), false) ic := &interop.Context{DAO: d} err := mgmt.Initialize(ic) @@ -97,7 +97,7 @@ func TestManagement_Initialize(t *testing.T) { func TestManagement_GetNEP17Contracts(t *testing.T) { mgmt := newManagement() - mgmt.Policy = newPolicy() + mgmt.Policy = newPolicy(false) d := dao.NewSimple(storage.NewMemoryStore(), false) err := mgmt.Initialize(&interop.Context{DAO: d}) require.NoError(t, err) diff --git a/pkg/core/native/native_gas.go b/pkg/core/native/native_gas.go index 7276572b6..6637085d1 100644 --- a/pkg/core/native/native_gas.go +++ b/pkg/core/native/native_gas.go @@ -18,9 +18,8 @@ import ( // GAS represents GAS native contract. type GAS struct { nep17TokenNative - NEO *NEO - // Notary is a native Notary contract. It is set only when P2PSigExtensions are on. - Notary *Notary + NEO *NEO + Policy *Policy initialSupply int64 p2pSigExtensionsEnabled bool @@ -124,7 +123,7 @@ func (g *GAS) OnPersist(ic *interop.Context) error { attrs := tx.GetAttributes(transaction.NotaryAssistedT) if len(attrs) != 0 { 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) } } } diff --git a/pkg/core/native/native_nep17.go b/pkg/core/native/native_nep17.go index da449f744..0d6d67b14 100644 --- a/pkg/core/native/native_nep17.go +++ b/pkg/core/native/native_nep17.go @@ -347,18 +347,30 @@ func toUint160(s stackitem.Item) util.Uint160 { return u } -func toUint32(s stackitem.Item) uint32 { +func toUint64(s stackitem.Item) uint64 { bigInt := toBigInt(s) 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 { panic("bigint does not fit into uint32") } 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 { bigInt := toBigInt(s) if !bigInt.IsInt64() { diff --git a/pkg/core/native/native_test/notary_test.go b/pkg/core/native/native_test/notary_test.go index 25cae19d8..67d100cc6 100644 --- a/pkg/core/native/native_test/notary_test.go +++ b/pkg/core/native/native_test/notary_test.go @@ -38,16 +38,6 @@ func TestNotary_MaxNotValidBeforeDeltaCache(t *testing.T) { 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) { notaryCommitteeInvoker := newNotaryClient(t) e := notaryCommitteeInvoker.Executor diff --git a/pkg/core/native/native_test/policy_test.go b/pkg/core/native/native_test/policy_test.go index 3d4a2c469..bb724ed67 100644 --- a/pkg/core/native/native_test/policy_test.go +++ b/pkg/core/native/native_test/policy_test.go @@ -7,8 +7,14 @@ import ( "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/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/smartcontract/callflag" "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 { @@ -39,6 +45,67 @@ func TestPolicy_StoragePriceCache(t *testing.T) { 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) { c := newPolicyClient(t) e := c.Executor diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go index c0b2da285..74c0c0dc5 100644 --- a/pkg/core/native/notary.go +++ b/pkg/core/native/notary.go @@ -28,14 +28,14 @@ import ( // Notary represents Notary native contract. type Notary struct { interop.ContractMD - GAS *GAS - NEO *NEO - Desig *Designate + GAS *GAS + NEO *NEO + Desig *Designate + Policy *Policy } type NotaryCache struct { maxNotValidBeforeDelta uint32 - notaryServiceFeePerKey int64 } // NotaryService is a Notary module interface. @@ -48,15 +48,10 @@ const ( // prefixDeposit is a prefix for storing Notary deposits. prefixDeposit = 1 defaultDepositDeltaTill = 5760 - 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 + defaultMaxNotValidBeforeDelta = 140 // 20 rounds for 7 validators, a little more than half an hour ) -var ( - maxNotValidBeforeDeltaKey = []byte{10} - notaryServiceFeeKey = []byte{5} -) +var maxNotValidBeforeDeltaKey = []byte{10} var ( _ interop.Contract = (*Notary)(nil) @@ -122,15 +117,6 @@ func newNotary() *Notary { md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 1<<15, callflag.States) 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 } @@ -142,11 +128,9 @@ func (n *Notary) Metadata() *interop.ContractMD { // Initialize initializes Notary native contract and implements the Contract interface. func (n *Notary) Initialize(ic *interop.Context) error { setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta) - setIntWithKey(n.ID, ic.DAO, notaryServiceFeeKey, defaultNotaryServiceFeePerKey) cache := &NotaryCache{ maxNotValidBeforeDelta: defaultMaxNotValidBeforeDelta, - notaryServiceFeePerKey: defaultNotaryServiceFeePerKey, } ic.DAO.SetCache(n.ID, cache) return nil @@ -155,7 +139,6 @@ func (n *Notary) Initialize(ic *interop.Context) error { func (n *Notary) InitializeCache(blockHeight uint32, d *dao.Simple) error { cache := &NotaryCache{ maxNotValidBeforeDelta: uint32(getIntWithKey(n.ID, d, maxNotValidBeforeDeltaKey)), - notaryServiceFeePerKey: getIntWithKey(n.ID, d, notaryServiceFeeKey), } d.SetCache(n.ID, cache) @@ -197,7 +180,7 @@ func (n *Notary) OnPersist(ic *interop.Context) error { if nFees == 0 { return nil } - feePerKey := n.GetNotaryServiceFeePerKey(ic.DAO) + feePerKey := n.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT) singleReward := calculateNotaryReward(nFees, feePerKey, len(notaries)) for _, notary := range notaries { 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 { 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 amount.Cmp(big.NewInt(2*feePerKey)) < 0 { 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{} } -// 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 // 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 { diff --git a/pkg/core/native/policy.go b/pkg/core/native/policy.go index d3fb5c001..cf9b39709 100644 --- a/pkg/core/native/policy.go +++ b/pkg/core/native/policy.go @@ -1,6 +1,7 @@ package native import ( + "encoding/hex" "fmt" "math/big" "sort" @@ -11,6 +12,7 @@ import ( "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/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/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" @@ -24,6 +26,10 @@ const ( defaultExecFeeFactor = interop.DefaultBaseExecFee defaultFeePerByte = 1000 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 = 100000 @@ -33,9 +39,13 @@ const ( maxFeePerByte = 100_000_000 // maxStoragePrice is the maximum allowed price for a byte of storage. 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 = 15 + // attributeFeePrefix is a prefix used to store attribute fee. + attributeFeePrefix = 20 ) var ( @@ -52,6 +62,9 @@ var ( type Policy struct { interop.ContractMD NEO *NEO + + // p2pSigExtensionsEnabled defines whether the P2P signature extensions logic is relevant. + p2pSigExtensionsEnabled bool } type PolicyCache struct { @@ -59,6 +72,7 @@ type PolicyCache struct { feePerByte int64 maxVerificationGas int64 storagePrice uint32 + attributeFee map[transaction.AttrType]uint32 blockedAccounts []util.Uint160 } @@ -76,13 +90,20 @@ func (c *PolicyCache) Copy() dao.NativeContractCache { func copyPolicyCache(src, dst *PolicyCache) { *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)) copy(dst.blockedAccounts, src.blockedAccounts) } // newPolicy returns Policy native contract. -func newPolicy() *Policy { - p := &Policy{ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID)} +func newPolicy(p2pSigExtensionsEnabled bool) *Policy { + p := &Policy{ + ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID), + p2pSigExtensionsEnabled: p2pSigExtensionsEnabled, + } defer p.UpdateHash() desc := newDescriptor("getFeePerByte", smartcontract.IntegerType) @@ -112,6 +133,17 @@ func newPolicy() *Policy { md = newMethodAndPrice(p.setStoragePrice, 1<<15, callflag.States) 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, manifest.NewParameter("value", smartcontract.IntegerType)) md = newMethodAndPrice(p.setFeePerByte, 1<<15, callflag.States) @@ -146,8 +178,13 @@ func (p *Policy) Initialize(ic *interop.Context) error { feePerByte: defaultFeePerByte, maxVerificationGas: defaultMaxVerificationGas, storagePrice: DefaultStoragePrice, + attributeFee: map[transaction.AttrType]uint32{}, 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) return nil @@ -183,6 +220,25 @@ func (p *Policy) fillCacheFromDAO(cache *PolicyCache, d *dao.Simple) error { if fErr != nil { 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 } @@ -297,6 +353,43 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta 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. func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stackitem.Item { value := toBigInt(args[0]).Int64() diff --git a/pkg/core/transaction/attrtype.go b/pkg/core/transaction/attrtype.go index c7a57f14c..e31f3b3ac 100644 --- a/pkg/core/transaction/attrtype.go +++ b/pkg/core/transaction/attrtype.go @@ -21,6 +21,15 @@ const ( 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 { switch a { case ConflictsT: @@ -29,3 +38,11 @@ func (a AttrType) allowMultiple() bool { 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 +} diff --git a/pkg/interop/native/notary/notary.go b/pkg/interop/native/notary/notary.go index d5668ed66..9246a1c87 100644 --- a/pkg/interop/native/notary/notary.go +++ b/pkg/interop/native/notary/notary.go @@ -45,13 +45,3 @@ func GetMaxNotValidBeforeDelta() int { func SetMaxNotValidBeforeDelta(value int) { 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) -} diff --git a/pkg/interop/native/policy/attrtype.go b/pkg/interop/native/policy/attrtype.go new file mode 100644 index 000000000..5c74d051d --- /dev/null +++ b/pkg/interop/native/policy/attrtype.go @@ -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 +) diff --git a/pkg/interop/native/policy/policy.go b/pkg/interop/native/policy/policy.go index b7aeeaca1..6e0fdc78e 100644 --- a/pkg/interop/native/policy/policy.go +++ b/pkg/interop/native/policy/policy.go @@ -43,6 +43,16 @@ func SetStoragePrice(value int) { 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. func IsBlocked(addr interop.Hash160) bool { return neogointernal.CallWithToken(Hash, "isBlocked", int(contract.ReadStates), addr).(bool) diff --git a/pkg/neotest/basic.go b/pkg/neotest/basic.go index d904f39ab..4e5a7eb4d 100644 --- a/pkg/neotest/basic.go +++ b/pkg/neotest/basic.go @@ -305,7 +305,7 @@ func AddNetworkFee(bc *core.Blockchain, tx *transaction.Transaction, signers ... tx.NetworkFee += netFee 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. diff --git a/pkg/rpcclient/notary/contract.go b/pkg/rpcclient/notary/contract.go index 3ded21bc5..7aee271bc 100644 --- a/pkg/rpcclient/notary/contract.go +++ b/pkg/rpcclient/notary/contract.go @@ -111,12 +111,6 @@ func (c *ContractReader) GetMaxNotValidBeforeDelta() (uint32, error) { 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 // 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 @@ -182,33 +176,6 @@ func (c *Contract) SetMaxNotValidBeforeDeltaUnsigned(blocks uint32) (*transactio 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 // 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 diff --git a/pkg/rpcclient/notary/contract_test.go b/pkg/rpcclient/notary/contract_test.go index 336c6ce88..170d247b7 100644 --- a/pkg/rpcclient/notary/contract_test.go +++ b/pkg/rpcclient/notary/contract_test.go @@ -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) { ta := new(testAct) ntr := New(ta) @@ -134,9 +114,6 @@ func TestTxSenders(t *testing.T) { "SetMaxNotValidBeforeDelta": func() (util.Uint256, uint32, error) { return ntr.SetMaxNotValidBeforeDelta(42) }, - "SetNotaryServiceFeePerKey": func() (util.Uint256, uint32, error) { - return ntr.SetNotaryServiceFeePerKey(100500) - }, "Withdraw": func() (util.Uint256, uint32, error) { 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) { 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) { return ntr.WithdrawTransaction(util.Uint160{1, 2, 3}, util.Uint160{3, 2, 1}) }, diff --git a/pkg/rpcclient/policy/policy.go b/pkg/rpcclient/policy/policy.go index 52dd6ba5b..d578f6273 100644 --- a/pkg/rpcclient/policy/policy.go +++ b/pkg/rpcclient/policy/policy.go @@ -40,6 +40,7 @@ const ( execFeeSetter = "setExecFeeFactor" feePerByteSetter = "setFeePerByte" storagePriceSetter = "setStoragePrice" + attributeFeeSetter = "setAttributeFee" ) // 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")) } +// 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. func (c *ContractReader) IsBlocked(account util.Uint160) (bool, error) { 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) } +// 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 // network (via `blockAccount` method), it fails (with FAULT state) if it's not // successful. The returned values are transaction hash, its diff --git a/pkg/rpcclient/policy/policy_test.go b/pkg/rpcclient/policy/policy_test.go index 458c77efd..c14022d84 100644 --- a/pkg/rpcclient/policy/policy_test.go +++ b/pkg/rpcclient/policy/policy_test.go @@ -58,6 +58,8 @@ func TestReader(t *testing.T) { } _, err := pc.IsBlocked(util.Uint160{1, 2, 3}) require.Error(t, err) + _, err = pc.GetAttributeFee(transaction.ConflictsT) + require.Error(t, err) ta.err = nil ta.res = &result.Invoke{ @@ -71,6 +73,9 @@ func TestReader(t *testing.T) { require.NoError(t, err) 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{ State: "HALT", Stack: []stackitem.Item{ @@ -97,6 +102,8 @@ func TestIntSetters(t *testing.T) { _, _, err := m(42) require.Error(t, err) } + _, _, err := pc.SetAttributeFee(transaction.OracleResponseT, 123) + require.Error(t, err) ta.err = nil 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.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) { diff --git a/pkg/services/rpcsrv/client_test.go b/pkg/services/rpcsrv/client_test.go index 31aaa3f0b..b77b44b0f 100644 --- a/pkg/services/rpcsrv/client_test.go +++ b/pkg/services/rpcsrv/client_test.go @@ -183,6 +183,10 @@ func TestClientPolicyContract(t *testing.T) { require.NoError(t, err) 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{}) require.NoError(t, err) require.False(t, ret) @@ -212,14 +216,17 @@ func TestClientPolicyContract(t *testing.T) { txstorage, err := polis.SetStoragePriceUnsigned(100500) require.NoError(t, err) + txattr, err := polis.SetAttributeFeeUnsigned(transaction.NotaryAssistedT, 100500) + require.NoError(t, err) + txblock, err := polis.BlockAccountUnsigned(util.Uint160{1, 2, 3}) 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) } - 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) require.NoError(t, err) @@ -235,6 +242,10 @@ func TestClientPolicyContract(t *testing.T) { require.NoError(t, err) 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}) require.NoError(t, err) require.True(t, ret) @@ -480,10 +491,6 @@ func TestClientNotary(t *testing.T) { require.NoError(t, err) 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{{ Signer: transaction.Signer{ Account: testchain.CommitteeScriptHash(), @@ -501,12 +508,9 @@ func TestClientNotary(t *testing.T) { txNVB, err := notaComm.SetMaxNotValidBeforeDeltaUnsigned(210) require.NoError(t, err) - txFee, err := notaComm.SetNotaryServiceFeePerKeyUnsigned(500_0000) - require.NoError(t, err) txNVB.Scripts[0].InvocationScript = testchain.SignCommittee(txNVB) - txFee.Scripts[0].InvocationScript = testchain.SignCommittee(txFee) - bl := testchain.NewBlock(t, chain, 1, 0, txNVB, txFee) + bl := testchain.NewBlock(t, chain, 1, 0, txNVB) _, err = c.SubmitBlock(*bl) require.NoError(t, err) @@ -514,10 +518,6 @@ func TestClientNotary(t *testing.T) { require.NoError(t, err) 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{{ Signer: transaction.Signer{ Account: priv0Hash, @@ -743,12 +743,13 @@ func TestCalculateNetworkFee(t *testing.T) { require.NoError(t, err) 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) { 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) require.NoError(t, err) tx.ValidUntilBlock = chain.BlockHeight() + 10 @@ -802,6 +803,62 @@ func TestCalculateNetworkFee(t *testing.T) { 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) { diff --git a/pkg/services/rpcsrv/server.go b/pkg/services/rpcsrv/server.go index 85e32069c..bb54fc4a3 100644 --- a/pkg/services/rpcsrv/server.go +++ b/pkg/services/rpcsrv/server.go @@ -65,6 +65,7 @@ type ( Ledger interface { AddBlock(block *block.Block) error BlockHeight() uint32 + CalculateAttributesFee(tx *transaction.Transaction) int64 CalculateClaimable(h util.Uint160, endHeight uint32) (*big.Int, error) CurrentBlockHash() util.Uint256 FeePerByte() int64 @@ -89,7 +90,6 @@ type ( GetNatives() []state.NativeContract GetNextBlockValidators() ([]*keys.PublicKey, error) GetNotaryContractScriptHash() util.Uint160 - GetNotaryServiceFeePerKey() int64 GetStateModule() core.StateRoot GetStorageItem(id int32, key []byte) state.StorageItem 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 size += io.GetVarSize(w.VerificationScript) + io.GetVarSize(w.InvocationScript) } - if s.chain.P2PSigExtensionsEnabled() { - 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 + netFee += int64(size)*s.chain.FeePerByte() + s.chain.CalculateAttributesFee(tx) return result.NetworkFee{Value: netFee}, nil } diff --git a/pkg/services/rpcsrv/server_helper_test.go b/pkg/services/rpcsrv/server_helper_test.go index e0a1ef68c..1d4115935 100644 --- a/pkg/services/rpcsrv/server_helper_test.go +++ b/pkg/services/rpcsrv/server_helper_test.go @@ -138,7 +138,7 @@ func initClearServerWithCustomConfig(t testing.TB, ccfg func(configuration *conf } 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) { diff --git a/pkg/services/rpcsrv/server_test.go b/pkg/services/rpcsrv/server_test.go index f559258a4..394f2678d 100644 --- a/pkg/services/rpcsrv/server_test.go +++ b/pkg/services/rpcsrv/server_test.go @@ -87,7 +87,7 @@ const ( faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60" faultedTxBlock uint32 = 23 invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA" - block20StateRootLE = "cc8315751c5b6edf39c14f1637bfa0595d6ca86b8ed4d41cb495d572b680504f" + block20StateRootLE = "858c873539d6d24a70f2be13f9dafc61aef2b63c2aa16bb440676de6e44e3cf1" ) var (