Merge pull request #2453 from nspcc-dev/check-policy-for-committee-members

Check policy for committee members
This commit is contained in:
Roman Khimov 2022-04-28 12:58:07 +03:00 committed by GitHub
commit 10acdbe40e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 24 deletions

View file

@ -77,19 +77,17 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions)
neo := newNEO()
policy := newPolicy()
neo.GAS = gas
neo.Policy = policy
gas.NEO = neo
mgmt.NEO = neo
policy.NEO = neo
cs.GAS = gas
cs.NEO = neo
cs.Contracts = append(cs.Contracts, neo)
cs.Contracts = append(cs.Contracts, gas)
policy := newPolicy()
policy.NEO = neo
cs.Policy = policy
cs.Contracts = append(cs.Contracts, policy)
cs.Contracts = append(cs.Contracts, neo, gas, policy)
desig := newDesignate(cfg.P2PSigExtensions)
desig.NEO = neo

View file

@ -20,10 +20,12 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"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/stackitem"
)
@ -31,6 +33,7 @@ import (
type NEO struct {
nep17TokenNative
GAS *GAS
Policy *Policy
// gasPerBlock represents current value of generated gas per block.
// It is append-only and doesn't need to be copied when used.
@ -822,11 +825,14 @@ func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *bi
func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool) ([]keyWithVotes, error) {
arr := make([]keyWithVotes, 0)
buf := io.NewBufBinWriter()
d.Seek(n.ID, storage.SeekRange{Prefix: []byte{prefixCandidate}}, func(k, v []byte) bool {
c := new(candidate).FromBytes(v)
if c.Registered {
emit.CheckSig(buf.BinWriter, k)
if c.Registered && !n.Policy.IsBlockedInternal(d, hash.Hash160(buf.Bytes())) {
arr = append(arr, keyWithVotes{Key: string(k), Votes: &c.Votes})
}
buf.Reset()
return true
})

View file

@ -49,6 +49,7 @@ func TestNEO_RegisterPrice(t *testing.T) {
func TestNEO_Vote(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()
@ -71,23 +72,23 @@ func TestNEO_Vote(t *testing.T) {
// voters vote for candidates. The aim of this test is to check that voting
// reward is proportional to the NEO balance.
voters := make([]neotest.Signer, committeeSize)
voters := make([]neotest.Signer, committeeSize+1)
// referenceAccounts perform the same actions as voters except voting, i.e. we
// will transfer the same amount of NEO to referenceAccounts and see how much
// GAS they receive for NEO ownership. We need these values to be able to define
// how much GAS voters receive for NEO ownership.
referenceAccounts := make([]neotest.Signer, committeeSize)
candidates := make([]neotest.Signer, committeeSize)
for i := 0; i < committeeSize; i++ {
referenceAccounts := make([]neotest.Signer, committeeSize+1)
candidates := make([]neotest.Signer, committeeSize+1)
for i := 0; i < committeeSize+1; i++ {
voters[i] = e.NewAccount(t, 10_0000_0000)
referenceAccounts[i] = e.NewAccount(t, 10_0000_0000)
candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
}
txes := make([]*transaction.Transaction, 0, committeeSize*4-2)
for i := 0; i < committeeSize; i++ {
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize-i)*1000000, nil)
for i := 0; i < committeeSize+1; i++ {
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
txes = append(txes, transferTx)
transferTx = neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), referenceAccounts[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize-i)*1000000, nil)
transferTx = neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), referenceAccounts[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
txes = append(txes, transferTx)
if i > 0 {
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
@ -96,6 +97,7 @@ func TestNEO_Vote(t *testing.T) {
txes = append(txes, voteTx)
}
}
txes = append(txes, policyInvoker.PrepareInvoke(t, "blockAccount", candidates[len(candidates)-1].(neotest.SingleSigner).Account().PrivateKey().PublicKey().GetScriptHash()))
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
@ -137,12 +139,12 @@ func TestNEO_Vote(t *testing.T) {
require.EqualValues(t, sortedCandidates, pubs)
t.Run("check voter rewards", func(t *testing.T) {
gasBalance := make([]*big.Int, len(voters))
referenceGASBalance := make([]*big.Int, len(referenceAccounts))
neoBalance := make([]*big.Int, len(voters))
txes = make([]*transaction.Transaction, 0, len(voters))
gasBalance := make([]*big.Int, len(voters)-1)
referenceGASBalance := make([]*big.Int, len(referenceAccounts)-1)
neoBalance := make([]*big.Int, len(voters)-1)
txes = make([]*transaction.Transaction, 0, len(voters)-1)
var refTxFee int64
for i := range voters {
for i := range voters[:len(voters)-1] {
h := voters[i].ScriptHash()
refH := referenceAccounts[i].ScriptHash()
gasBalance[i] = e.Chain.GetUtilityTokenBalance(h)
@ -169,7 +171,7 @@ func TestNEO_Vote(t *testing.T) {
// GAS increase consists of 2 parts: NEO holding + voting for committee nodes.
// Here we check that 2-nd part exists and is proportional to the amount of NEO given.
for i := range voters {
for i := range voters[:len(voters)-1] {
newGAS := e.Chain.GetUtilityTokenBalance(voters[i].ScriptHash())
newGAS.Sub(newGAS, gasBalance[i])
gasForHold := referenceGASBalance[i]
@ -197,6 +199,7 @@ func TestNEO_Vote(t *testing.T) {
require.NoError(t, err)
for i := range pubs {
require.NotEqual(t, candidates[0], pubs[i])
require.NotEqual(t, candidates[len(candidates)-1], pubs[i])
}
}

View file

@ -12,7 +12,6 @@ import (
"github.com/btcsuite/btcd/btcec"
lru "github.com/hashicorp/golang-lru"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io"
@ -319,8 +318,7 @@ func (p *PublicKey) GetVerificationScript() []byte {
buf.WriteB(0xAC) // CHECKSIG
return buf.Bytes()
}
emit.Bytes(buf.BinWriter, b)
emit.Syscall(buf.BinWriter, interopnames.SystemCryptoCheckSig)
emit.CheckSig(buf.BinWriter, b)
return buf.Bytes()
}

View file

@ -219,6 +219,14 @@ func AppCall(w *io.BinWriter, scriptHash util.Uint160, operation string, f callf
AppCallNoArgs(w, scriptHash, operation, f)
}
// CheckSig emits a single-key verification script using given []bytes as a key.
// It does not check for key correctness, so you can get an invalid script if the
// data passed is not really a public key.
func CheckSig(w *io.BinWriter, key []byte) {
Bytes(w, key)
Syscall(w, interopnames.SystemCryptoCheckSig)
}
func isInstructionJmp(op opcode.Opcode) bool {
return opcode.JMP <= op && op <= opcode.CALLL || op == opcode.ENDTRYL
}