Merge pull request #2465 from nspcc-dev/get-candidates

core: refactor native Neo's GetCandidates
This commit is contained in:
Roman Khimov 2022-05-06 14:02:54 +03:00 committed by GitHub
commit 697c73626a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 241 additions and 64 deletions

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -3,7 +3,7 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd-nns
go 1.16
require (
github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220429082343-69b70c5e933a
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220506104421-8802dcf05412
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb
github.com/stretchr/testify v1.7.0
)

View file

@ -49,6 +49,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -177,10 +179,10 @@ github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU=
github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg=
github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220429082343-69b70c5e933a h1:5tTKYXxz/DRDopPpf2/2rcdkESDm/RWH3t5aNXyGtAc=
github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220429082343-69b70c5e933a/go.mod h1:hKgAWnSYaq5FIg8XclLvG5gjsjjFMkFhklyO092/sGM=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220506104421-8802dcf05412 h1:poYvGwGXV8GQtci7pMFVzkmldORD25Gb6Qn3t9ZWw2o=
github.com/nspcc-dev/neo-go v0.98.3-pre.0.20220506104421-8802dcf05412/go.mod h1:u8Ftsdadsm3DHLO+XGQOM/iaTwPPRtOhZH3sM43xgQI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token
go 1.16
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=

2
go.mod
View file

@ -12,7 +12,7 @@ require (
github.com/mr-tron/base58 v1.2.0
github.com/nspcc-dev/dbft v0.0.0-20220414131237-e497bbf7868e
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659
github.com/nspcc-dev/rfc6979 v0.2.0
github.com/pierrec/lz4 v2.6.1+incompatible

4
go.sum
View file

@ -185,8 +185,8 @@ github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU=
github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg=
github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47 h1:9PVLOwD2khKIb4BQR7nqeslE1pRSGxJoXvul2/Rk1wY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220429082221-441a3eb34c47/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb h1:7WtIzIsP+y6yWQVFMAICs5ShY0Q5EHzTWa4503XmHkI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220506104312-5123b88c36cb/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=

View file

@ -144,6 +144,8 @@ func TestNativeHelpersCompile(t *testing.T) {
}
runNativeTestCases(t, cs.NEO.ContractMD, "neo", append([]nativeTestCase{
{"getCandidates", nil},
{"getAllCandidates", nil},
{"getCandidateVote", []string{pub}},
{"getCommittee", nil},
{"getGasPerBlock", nil},
{"getNextBlockValidators", nil},

View file

@ -839,14 +839,13 @@ func (dao *Simple) getDataBuf() *io.BufBinWriter {
// underlying store. It doesn't block accesses to DAO from other threads.
func (dao *Simple) Persist() (int, error) {
if dao.nativeCachePS != nil {
if !dao.private {
dao.nativeCacheLock.Lock()
defer dao.nativeCacheLock.Unlock()
}
if !dao.nativeCachePS.private {
dao.nativeCachePS.nativeCacheLock.Lock()
defer dao.nativeCachePS.nativeCacheLock.Unlock()
}
defer func() {
dao.nativeCachePS.nativeCacheLock.Unlock()
dao.nativeCacheLock.Unlock()
}()
dao.persistNativeCache()
}
return dao.Store.Persist()
@ -881,10 +880,8 @@ func (dao *Simple) persistNativeCache() {
// GetROCache returns native contact cache. The cache CAN NOT be modified by
// the caller. It's the caller's duty to keep it unmodified.
func (dao *Simple) GetROCache(id int32) NativeContractCache {
if !dao.private {
dao.nativeCacheLock.RLock()
defer dao.nativeCacheLock.RUnlock()
}
return dao.getCache(id, true)
}
@ -892,10 +889,8 @@ func (dao *Simple) GetROCache(id int32) NativeContractCache {
// GetRWCache returns native contact cache. The cache CAN BE safely modified
// by the caller.
func (dao *Simple) GetRWCache(id int32) NativeContractCache {
if !dao.private {
dao.nativeCacheLock.Lock()
defer dao.nativeCacheLock.Unlock()
}
return dao.getCache(id, false)
}

View file

@ -1,6 +1,7 @@
package native
import (
"context"
"crypto/elliptic"
"encoding/binary"
"errors"
@ -13,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
istorage "github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
@ -91,6 +93,10 @@ const (
committeeRewardRatio = 10
// neoHolderRewardRatio is a percent of generated GAS that is distributed to voters.
voterRewardRatio = 80
// maxGetCandidatesRespLen is the maximum number of candidates to return from the
// getCandidates method.
maxGetCandidatesRespLen = 256
)
var (
@ -194,6 +200,15 @@ func newNEO(cfg config.ProtocolConfiguration) *NEO {
md = newMethodAndPrice(n.getCandidatesCall, 1<<22, callflag.ReadStates)
n.AddMethod(md, desc)
desc = newDescriptor("getAllCandidates", smartcontract.InteropInterfaceType)
md = newMethodAndPrice(n.getAllCandidatesCall, 1<<22, callflag.ReadStates)
n.AddMethod(md, desc)
desc = newDescriptor("getCandidateVote", smartcontract.IntegerType,
manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
md = newMethodAndPrice(n.getCandidateVoteCall, 1<<15, callflag.ReadStates)
n.AddMethod(md, desc)
desc = newDescriptor("getAccountState", smartcontract.ArrayType,
manifest.NewParameter("account", smartcontract.Hash160Type))
md = newMethodAndPrice(n.getAccountState, 1<<15, callflag.ReadStates)
@ -851,7 +866,7 @@ func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *bi
return nil
}
func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool) ([]keyWithVotes, error) {
func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool, max int) ([]keyWithVotes, error) {
arr := make([]keyWithVotes, 0)
buf := io.NewBufBinWriter()
d.Seek(n.ID, storage.SeekRange{Prefix: []byte{prefixCandidate}}, func(k, v []byte) bool {
@ -861,7 +876,7 @@ func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool) ([]keyWithVotes, erro
arr = append(arr, keyWithVotes{Key: string(k), Votes: &c.Votes})
}
buf.Reset()
return true
return !sortByKey || max > 0 && len(arr) < max
})
if !sortByKey {
@ -893,7 +908,7 @@ func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool) ([]keyWithVotes, erro
// GetCandidates returns current registered validators list with keys
// and votes.
func (n *NEO) GetCandidates(d *dao.Simple) ([]state.Validator, error) {
kvs, err := n.getCandidates(d, true)
kvs, err := n.getCandidates(d, true, maxGetCandidatesRespLen)
if err != nil {
return nil, err
}
@ -909,7 +924,7 @@ func (n *NEO) GetCandidates(d *dao.Simple) ([]state.Validator, error) {
}
func (n *NEO) getCandidatesCall(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
validators, err := n.getCandidates(ic.DAO, true)
validators, err := n.getCandidates(ic.DAO, true, maxGetCandidatesRespLen)
if err != nil {
panic(err)
}
@ -923,6 +938,51 @@ func (n *NEO) getCandidatesCall(ic *interop.Context, _ []stackitem.Item) stackit
return stackitem.NewArray(arr)
}
func (n *NEO) getAllCandidatesCall(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
ctx, cancel := context.WithCancel(context.Background())
prefix := []byte{prefixCandidate}
buf := io.NewBufBinWriter()
keep := func(kv storage.KeyValue) bool {
c := new(candidate).FromBytes(kv.Value)
emit.CheckSig(buf.BinWriter, kv.Key)
if c.Registered && !n.Policy.IsBlocked(ic.DAO, hash.Hash160(buf.Bytes())) {
buf.Reset()
return true
}
buf.Reset()
return false
}
seekres := ic.DAO.SeekAsync(ctx, n.ID, storage.SeekRange{Prefix: prefix})
filteredRes := make(chan storage.KeyValue)
go func() {
for kv := range seekres {
if keep(kv) {
filteredRes <- kv
}
}
close(filteredRes)
}()
opts := istorage.FindRemovePrefix | istorage.FindDeserialize | istorage.FindPick1
item := istorage.NewIterator(filteredRes, prefix, int64(opts))
ic.RegisterCancelFunc(cancel)
return stackitem.NewInterop(item)
}
func (n *NEO) getCandidateVoteCall(ic *interop.Context, args []stackitem.Item) stackitem.Item {
pub := toPublicKey(args[0])
key := makeValidatorKey(pub)
si := ic.DAO.GetStorageItem(n.ID, key)
if si == nil {
return stackitem.NewBigInteger(big.NewInt(-1))
}
c := new(candidate).FromBytes(si)
if !c.Registered {
return stackitem.NewBigInteger(big.NewInt(-1))
}
return stackitem.NewBigInteger(&c.Votes)
}
func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stackitem.Item {
key := makeAccountKey(toUint160(args[0]))
si := ic.DAO.GetStorageItem(n.ID, key)
@ -1021,7 +1081,7 @@ func (n *NEO) computeCommitteeMembers(blockHeight uint32, d *dao.Simple) (keys.P
count := n.cfg.GetCommitteeSize(blockHeight + 1)
// Can be sorted and/or returned to outside users, thus needs to be copied.
sbVals := keys.PublicKeys(n.standbyKeys[:count]).Copy()
cs, err := n.getCandidates(d, false)
cs, err := n.getCandidates(d, false, -1)
if err != nil {
return nil, nil, err
}

View file

@ -1,6 +1,7 @@
package native_test
import (
"bytes"
"encoding/json"
"math"
"math/big"
@ -9,15 +10,20 @@ import (
"github.com/nspcc-dev/neo-go/internal/contracts"
"github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"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/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"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"
"github.com/stretchr/testify/require"
)
@ -482,3 +488,88 @@ func TestNEO_CalculateBonus(t *testing.T) {
claimTx.SystemFee-claimTx.NetworkFee + +firstPart + secondPart))
})
}
func TestNEO_GetCandidates(t *testing.T) {
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
policyInvoker := neoCommitteeInvoker.CommitteeInvoker(neoCommitteeInvoker.NativeHash(t, nativenames.Policy))
e := neoCommitteeInvoker.Executor
cfg := e.Chain.GetConfig()
candidatesCount := cfg.GetCommitteeSize(0) - 1
// Register a set of candidates and vote for them.
voters := make([]neotest.Signer, candidatesCount)
candidates := make([]neotest.Signer, candidatesCount)
for i := 0; i < candidatesCount; i++ {
voters[i] = e.NewAccount(t, 10_0000_0000)
candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
}
txes := make([]*transaction.Transaction, 0, candidatesCount*3)
for i := 0; i < candidatesCount; i++ {
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(candidatesCount+1-i)*1000000, nil)
txes = append(txes, transferTx)
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
txes = append(txes, registerTx)
voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
txes = append(txes, voteTx)
}
neoValidatorsInvoker.AddNewBlock(t, txes...)
for _, tx := range txes {
e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
}
expected := make([]stackitem.Item, candidatesCount)
for i := range expected {
pub := candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes()
v := stackitem.NewBigInteger(big.NewInt(int64(candidatesCount-i+1) * 1000000))
expected[i] = stackitem.NewStruct([]stackitem.Item{
stackitem.NewByteArray(pub),
v,
})
neoCommitteeInvoker.Invoke(t, v, "getCandidateVote", pub)
}
sort.Slice(expected, func(i, j int) bool {
return bytes.Compare(expected[i].Value().([]stackitem.Item)[0].Value().([]byte), expected[j].Value().([]stackitem.Item)[0].Value().([]byte)) < 0
})
neoCommitteeInvoker.Invoke(t, stackitem.NewArray(expected), "getCandidates")
// Check that GetAllCandidates works the same way as GetCandidates.
checkGetAllCandidates := func(t *testing.T, expected []stackitem.Item) {
for i := 0; i < len(expected)+1; i++ {
w := io.NewBufBinWriter()
emit.AppCall(w.BinWriter, neoCommitteeInvoker.Hash, "getAllCandidates", callflag.All)
for j := 0; j < i+1; j++ {
emit.Opcodes(w.BinWriter, opcode.DUP)
emit.Syscall(w.BinWriter, interopnames.SystemIteratorNext)
emit.Opcodes(w.BinWriter, opcode.DROP) // drop the value returned from Next.
}
emit.Syscall(w.BinWriter, interopnames.SystemIteratorValue)
require.NoError(t, w.Err)
h := neoCommitteeInvoker.InvokeScript(t, w.Bytes(), neoCommitteeInvoker.Signers)
if i < len(expected) {
e.CheckHalt(t, h, expected[i])
} else {
e.CheckFault(t, h, "iterator index out of range") // ensure there are no extra elements.
}
w.Reset()
}
}
checkGetAllCandidates(t, expected)
// Block candidate and check it won't be returned from getCandidates and getAllCandidates.
unlucky := candidates[len(candidates)-1].(neotest.SingleSigner).Account().PrivateKey().PublicKey()
policyInvoker.Invoke(t, true, "blockAccount", unlucky.GetScriptHash())
for i := range expected {
if bytes.Equal(expected[i].Value().([]stackitem.Item)[0].Value().([]byte), unlucky.Bytes()) {
if i != len(expected)-1 {
expected = append(expected[:i], expected[i+1:]...)
} else {
expected = expected[:i]
}
break
}
}
neoCommitteeInvoker.Invoke(t, expected, "getCandidates")
checkGetAllCandidates(t, expected)
}

View file

@ -9,6 +9,7 @@ package neo
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
)
@ -53,9 +54,26 @@ func GetCommittee() []interop.PublicKey {
return neogointernal.CallWithToken(Hash, "getCommittee", int(contract.ReadStates)).([]interop.PublicKey)
}
// GetCandidates represents `getCandidates` method of NEO native contract.
func GetCandidates() []interop.PublicKey {
return neogointernal.CallWithToken(Hash, "getCandidates", int(contract.ReadStates)).([]interop.PublicKey)
// GetCandidates represents `getCandidates` method of NEO native contract. It
// returns up to 256 candidates. Use GetAllCandidates in case if you need the
// whole set of candidates.
func GetCandidates() []Candidate {
return neogointernal.CallWithToken(Hash, "getCandidates", int(contract.ReadStates)).([]Candidate)
}
// GetAllCandidates represents `getAllCandidates` method of NEO native contract.
// It returns Iterator over the whole set of Neo candidates sorted by public key
// bytes. Each iterator value can be cast to Candidate. Use iterator interop
// package to work with the returned Iterator.
func GetAllCandidates() iterator.Iterator {
return neogointernal.CallWithToken(Hash, "getAllCandidates", int(contract.ReadStates)).(iterator.Iterator)
}
// GetCandidateVote represents `getCandidateVote` method of NEO native contract.
// It returns -1 if the candidate hasn't been registered or voted for and the
// overall candidate votes otherwise.
func GetCandidateVote(pub interop.PublicKey) int {
return neogointernal.CallWithToken(Hash, "getCandidateVote", int(contract.ReadStates), pub).(int)
}
// GetNextBlockValidators represents `getNextBlockValidators` method of NEO native contract.

View file

@ -0,0 +1,9 @@
package neo
import "github.com/nspcc-dev/neo-go/pkg/interop"
// Candidate represents a single native Neo candidate.
type Candidate struct {
Key interop.PublicKey
Votes int
}

View file

@ -75,7 +75,7 @@ const (
nfsoContractHash = "5f9ebd6b001b54c7bc70f96e0412fcf415dfe09f"
nfsoToken1ID = "7e244ffd6aa85fb1579d2ed22e9b761ab62e3486"
invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA"
block20StateRootLE = "19ec3c3d01afe5274e8bb4a393c97da708c5608c5b0ad116c16108b6a04fb08e"
block20StateRootLE = "0fbb19143cb782df2c893d448a89ec959bea8bf467faf747638975812d570f72"
)
var (