forked from TrueCloudLab/neoneo-go
Merge pull request #2453 from nspcc-dev/check-policy-for-committee-members
Check policy for committee members
This commit is contained in:
commit
10acdbe40e
5 changed files with 37 additions and 24 deletions
|
@ -77,19 +77,17 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
|
||||||
|
|
||||||
gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions)
|
gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions)
|
||||||
neo := newNEO()
|
neo := newNEO()
|
||||||
|
policy := newPolicy()
|
||||||
neo.GAS = gas
|
neo.GAS = gas
|
||||||
|
neo.Policy = policy
|
||||||
gas.NEO = neo
|
gas.NEO = neo
|
||||||
mgmt.NEO = neo
|
mgmt.NEO = neo
|
||||||
|
policy.NEO = neo
|
||||||
|
|
||||||
cs.GAS = gas
|
cs.GAS = gas
|
||||||
cs.NEO = neo
|
cs.NEO = neo
|
||||||
cs.Contracts = append(cs.Contracts, neo)
|
|
||||||
cs.Contracts = append(cs.Contracts, gas)
|
|
||||||
|
|
||||||
policy := newPolicy()
|
|
||||||
policy.NEO = neo
|
|
||||||
cs.Policy = policy
|
cs.Policy = policy
|
||||||
cs.Contracts = append(cs.Contracts, policy)
|
cs.Contracts = append(cs.Contracts, neo, gas, policy)
|
||||||
|
|
||||||
desig := newDesignate(cfg.P2PSigExtensions)
|
desig := newDesignate(cfg.P2PSigExtensions)
|
||||||
desig.NEO = neo
|
desig.NEO = neo
|
||||||
|
|
|
@ -20,17 +20,20 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"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/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
"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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NEO represents NEO native contract.
|
// NEO represents NEO native contract.
|
||||||
type NEO struct {
|
type NEO struct {
|
||||||
nep17TokenNative
|
nep17TokenNative
|
||||||
GAS *GAS
|
GAS *GAS
|
||||||
|
Policy *Policy
|
||||||
|
|
||||||
// gasPerBlock represents current value of generated gas per block.
|
// gasPerBlock represents current value of generated gas per block.
|
||||||
// It is append-only and doesn't need to be copied when used.
|
// 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) {
|
func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool) ([]keyWithVotes, error) {
|
||||||
arr := make([]keyWithVotes, 0)
|
arr := make([]keyWithVotes, 0)
|
||||||
|
buf := io.NewBufBinWriter()
|
||||||
d.Seek(n.ID, storage.SeekRange{Prefix: []byte{prefixCandidate}}, func(k, v []byte) bool {
|
d.Seek(n.ID, storage.SeekRange{Prefix: []byte{prefixCandidate}}, func(k, v []byte) bool {
|
||||||
c := new(candidate).FromBytes(v)
|
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})
|
arr = append(arr, keyWithVotes{Key: string(k), Votes: &c.Votes})
|
||||||
}
|
}
|
||||||
|
buf.Reset()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ func TestNEO_RegisterPrice(t *testing.T) {
|
||||||
func TestNEO_Vote(t *testing.T) {
|
func TestNEO_Vote(t *testing.T) {
|
||||||
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
|
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
|
||||||
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
|
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
|
||||||
|
policyInvoker := neoCommitteeInvoker.CommitteeInvoker(neoCommitteeInvoker.NativeHash(t, nativenames.Policy))
|
||||||
e := neoCommitteeInvoker.Executor
|
e := neoCommitteeInvoker.Executor
|
||||||
|
|
||||||
cfg := e.Chain.GetConfig()
|
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
|
// voters vote for candidates. The aim of this test is to check that voting
|
||||||
// reward is proportional to the NEO balance.
|
// 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
|
// 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
|
// 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
|
// GAS they receive for NEO ownership. We need these values to be able to define
|
||||||
// how much GAS voters receive for NEO ownership.
|
// how much GAS voters receive for NEO ownership.
|
||||||
referenceAccounts := make([]neotest.Signer, committeeSize)
|
referenceAccounts := make([]neotest.Signer, committeeSize+1)
|
||||||
candidates := make([]neotest.Signer, committeeSize)
|
candidates := make([]neotest.Signer, committeeSize+1)
|
||||||
for i := 0; i < committeeSize; i++ {
|
for i := 0; i < committeeSize+1; i++ {
|
||||||
voters[i] = e.NewAccount(t, 10_0000_0000)
|
voters[i] = e.NewAccount(t, 10_0000_0000)
|
||||||
referenceAccounts[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
|
candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
|
||||||
}
|
}
|
||||||
txes := make([]*transaction.Transaction, 0, committeeSize*4-2)
|
txes := make([]*transaction.Transaction, 0, committeeSize*4-2)
|
||||||
for i := 0; i < committeeSize; i++ {
|
for i := 0; i < committeeSize+1; i++ {
|
||||||
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize-i)*1000000, nil)
|
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)
|
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)
|
txes = append(txes, transferTx)
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
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, voteTx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
txes = append(txes, policyInvoker.PrepareInvoke(t, "blockAccount", candidates[len(candidates)-1].(neotest.SingleSigner).Account().PrivateKey().PublicKey().GetScriptHash()))
|
||||||
neoValidatorsInvoker.AddNewBlock(t, txes...)
|
neoValidatorsInvoker.AddNewBlock(t, txes...)
|
||||||
for _, tx := range txes {
|
for _, tx := range txes {
|
||||||
e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
|
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)
|
require.EqualValues(t, sortedCandidates, pubs)
|
||||||
|
|
||||||
t.Run("check voter rewards", func(t *testing.T) {
|
t.Run("check voter rewards", func(t *testing.T) {
|
||||||
gasBalance := make([]*big.Int, len(voters))
|
gasBalance := make([]*big.Int, len(voters)-1)
|
||||||
referenceGASBalance := make([]*big.Int, len(referenceAccounts))
|
referenceGASBalance := make([]*big.Int, len(referenceAccounts)-1)
|
||||||
neoBalance := make([]*big.Int, len(voters))
|
neoBalance := make([]*big.Int, len(voters)-1)
|
||||||
txes = make([]*transaction.Transaction, 0, len(voters))
|
txes = make([]*transaction.Transaction, 0, len(voters)-1)
|
||||||
var refTxFee int64
|
var refTxFee int64
|
||||||
for i := range voters {
|
for i := range voters[:len(voters)-1] {
|
||||||
h := voters[i].ScriptHash()
|
h := voters[i].ScriptHash()
|
||||||
refH := referenceAccounts[i].ScriptHash()
|
refH := referenceAccounts[i].ScriptHash()
|
||||||
gasBalance[i] = e.Chain.GetUtilityTokenBalance(h)
|
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.
|
// 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.
|
// 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 := e.Chain.GetUtilityTokenBalance(voters[i].ScriptHash())
|
||||||
newGAS.Sub(newGAS, gasBalance[i])
|
newGAS.Sub(newGAS, gasBalance[i])
|
||||||
gasForHold := referenceGASBalance[i]
|
gasForHold := referenceGASBalance[i]
|
||||||
|
@ -197,6 +199,7 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for i := range pubs {
|
for i := range pubs {
|
||||||
require.NotEqual(t, candidates[0], pubs[i])
|
require.NotEqual(t, candidates[0], pubs[i])
|
||||||
|
require.NotEqual(t, candidates[len(candidates)-1], pubs[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
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/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
|
@ -319,8 +318,7 @@ func (p *PublicKey) GetVerificationScript() []byte {
|
||||||
buf.WriteB(0xAC) // CHECKSIG
|
buf.WriteB(0xAC) // CHECKSIG
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
emit.Bytes(buf.BinWriter, b)
|
emit.CheckSig(buf.BinWriter, b)
|
||||||
emit.Syscall(buf.BinWriter, interopnames.SystemCryptoCheckSig)
|
|
||||||
|
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,6 +219,14 @@ func AppCall(w *io.BinWriter, scriptHash util.Uint160, operation string, f callf
|
||||||
AppCallNoArgs(w, scriptHash, operation, f)
|
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 {
|
func isInstructionJmp(op opcode.Opcode) bool {
|
||||||
return opcode.JMP <= op && op <= opcode.CALLL || op == opcode.ENDTRYL
|
return opcode.JMP <= op && op <= opcode.CALLL || op == opcode.ENDTRYL
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue