mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 23:25:22 +00:00
core: switch to the new voting system (via native NEO contract)
It has all the methods required now, so you can register, vote and get voting results. Fixes #865.
This commit is contained in:
parent
2fa3bdf6a9
commit
b83e84ca08
13 changed files with 42 additions and 399 deletions
|
@ -479,22 +479,12 @@ func (s *service) getVerifiedTx(count int) []block.Transaction {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) getValidators(txx ...block.Transaction) []crypto.PublicKey {
|
func (s *service) getValidators(_ ...block.Transaction) []crypto.PublicKey {
|
||||||
var (
|
var (
|
||||||
pKeys []*keys.PublicKey
|
pKeys []*keys.PublicKey
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if len(txx) == 0 {
|
|
||||||
pKeys, err = s.Chain.GetValidators()
|
pKeys, err = s.Chain.GetValidators()
|
||||||
} else {
|
|
||||||
ntxx := make([]*transaction.Transaction, len(txx))
|
|
||||||
for i := range ntxx {
|
|
||||||
ntxx[i] = txx[i].(*transaction.Transaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
pKeys, err = s.Chain.GetValidators(ntxx...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Error("error while trying to get validators", zap.Error(err))
|
s.log.Error("error while trying to get validators", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -630,14 +630,6 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *transaction.EnrollmentTX:
|
|
||||||
if err := processEnrollmentTX(cache, t); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case *transaction.StateTX:
|
|
||||||
if err := bc.processStateTX(cache, tx, t); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case *transaction.InvocationTX:
|
case *transaction.InvocationTX:
|
||||||
systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx)
|
systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx)
|
||||||
v := SpawnVM(systemInterop)
|
v := SpawnVM(systemInterop)
|
||||||
|
@ -839,26 +831,6 @@ func processOutputs(tx *transaction.Transaction, dao *dao.Cached) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processValidatorStateDescriptor(descriptor *transaction.StateDescriptor, dao *dao.Cached) error {
|
|
||||||
publicKey := &keys.PublicKey{}
|
|
||||||
err := publicKey.DecodeBytes(descriptor.Key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
validatorState, err := dao.GetValidatorStateOrNew(publicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if descriptor.Field == "Registered" {
|
|
||||||
if len(descriptor.Value) == 1 {
|
|
||||||
validatorState.Registered = descriptor.Value[0] != 0
|
|
||||||
return dao.PutValidatorState(validatorState)
|
|
||||||
}
|
|
||||||
return errors.New("bad descriptor value")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bc *Blockchain) processAccountStateDescriptor(descriptor *transaction.StateDescriptor, t *transaction.Transaction, dao *dao.Cached) error {
|
func (bc *Blockchain) processAccountStateDescriptor(descriptor *transaction.StateDescriptor, t *transaction.Transaction, dao *dao.Cached) error {
|
||||||
hash, err := util.Uint160DecodeBytesBE(descriptor.Key)
|
hash, err := util.Uint160DecodeBytesBE(descriptor.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1335,7 +1307,7 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
|
||||||
for _, k := range votes {
|
for _, k := range votes {
|
||||||
var isRegistered bool
|
var isRegistered bool
|
||||||
for i := range validators {
|
for i := range validators {
|
||||||
if k.Equal(validators[i].PublicKey) {
|
if k.Equal(validators[i].Key) {
|
||||||
isRegistered = true
|
isRegistered = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -1631,128 +1603,14 @@ func (bc *Blockchain) GetStandByValidators() (keys.PublicKeys, error) {
|
||||||
return getValidators(bc.config)
|
return getValidators(bc.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValidators returns validators.
|
// GetValidators returns next block validators.
|
||||||
// Golang implementation of GetValidators method in C# (https://github.com/neo-project/neo/blob/c64748ecbac3baeb8045b16af0d518398a6ced24/neo/Persistence/Snapshot.cs#L182)
|
func (bc *Blockchain) GetValidators() ([]*keys.PublicKey, error) {
|
||||||
func (bc *Blockchain) GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error) {
|
return bc.contracts.NEO.GetNextBlockValidatorsInternal(bc, bc.dao)
|
||||||
cache := dao.NewCached(bc.dao)
|
|
||||||
if len(txes) > 0 {
|
|
||||||
for _, tx := range txes {
|
|
||||||
// iterate through outputs
|
|
||||||
for index, output := range tx.Outputs {
|
|
||||||
accountState, err := cache.GetAccountStateOrNew(output.ScriptHash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
accountState.Balances[output.AssetID] = append(accountState.Balances[output.AssetID], state.UnspentBalance{
|
|
||||||
Tx: tx.Hash(),
|
|
||||||
Index: uint16(index),
|
|
||||||
Value: output.Amount,
|
|
||||||
})
|
|
||||||
if err := cache.PutAccountState(accountState); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// group inputs by the same previous hash and iterate through inputs
|
// GetEnrollments returns all registered validators.
|
||||||
group := make(map[util.Uint256][]*transaction.Input)
|
func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
|
||||||
for i := range tx.Inputs {
|
return bc.contracts.NEO.GetRegisteredValidators(bc.dao)
|
||||||
hash := tx.Inputs[i].PrevHash
|
|
||||||
group[hash] = append(group[hash], &tx.Inputs[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
for hash, inputs := range group {
|
|
||||||
unspent, err := cache.GetUnspentCoinState(hash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// process inputs
|
|
||||||
for _, input := range inputs {
|
|
||||||
prevOutput := &unspent.States[input.PrevIndex].Output
|
|
||||||
accountState, err := cache.GetAccountStateOrNew(prevOutput.ScriptHash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(accountState.Balances, prevOutput.AssetID)
|
|
||||||
if err = cache.PutAccountState(accountState); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := tx.Data.(type) {
|
|
||||||
case *transaction.EnrollmentTX:
|
|
||||||
if err := processEnrollmentTX(cache, t); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case *transaction.StateTX:
|
|
||||||
if err := bc.processStateTX(cache, tx, t); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bc.contracts.NEO.GetValidatorsInternal(bc, cache)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetEnrollments returns all registered validators and non-registered SB validators
|
|
||||||
func (bc *Blockchain) GetEnrollments() ([]*state.Validator, error) {
|
|
||||||
validators := bc.dao.GetValidators()
|
|
||||||
standByValidators, err := bc.GetStandByValidators()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
uniqueSBValidators := standByValidators.Unique()
|
|
||||||
|
|
||||||
var result []*state.Validator
|
|
||||||
for _, validator := range validators {
|
|
||||||
if validator.Registered {
|
|
||||||
result = append(result, validator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, sBValidator := range uniqueSBValidators {
|
|
||||||
isAdded := false
|
|
||||||
for _, v := range result {
|
|
||||||
if v.PublicKey == sBValidator {
|
|
||||||
isAdded = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !isAdded {
|
|
||||||
result = append(result, &state.Validator{
|
|
||||||
PublicKey: sBValidator,
|
|
||||||
Registered: false,
|
|
||||||
Votes: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bc *Blockchain) processStateTX(dao *dao.Cached, t *transaction.Transaction, tx *transaction.StateTX) error {
|
|
||||||
for _, desc := range tx.Descriptors {
|
|
||||||
switch desc.Type {
|
|
||||||
case transaction.Account:
|
|
||||||
if err := bc.processAccountStateDescriptor(desc, t, dao); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case transaction.Validator:
|
|
||||||
if err := processValidatorStateDescriptor(desc, dao); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func processEnrollmentTX(dao *dao.Cached, tx *transaction.EnrollmentTX) error {
|
|
||||||
validatorState, err := dao.GetValidatorStateOrNew(&tx.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
validatorState.Registered = true
|
|
||||||
return dao.PutValidatorState(validatorState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetScriptHashesForVerifying returns all the ScriptHashes of a transaction which will be use
|
// GetScriptHashesForVerifying returns all the ScriptHashes of a transaction which will be use
|
||||||
|
|
|
@ -24,7 +24,7 @@ type Blockchainer interface {
|
||||||
HeaderHeight() uint32
|
HeaderHeight() uint32
|
||||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||||
GetContractState(hash util.Uint160) *state.Contract
|
GetContractState(hash util.Uint160) *state.Contract
|
||||||
GetEnrollments() ([]*state.Validator, error)
|
GetEnrollments() ([]state.Validator, error)
|
||||||
GetHeaderHash(int) util.Uint256
|
GetHeaderHash(int) util.Uint256
|
||||||
GetHeader(hash util.Uint256) (*block.Header, error)
|
GetHeader(hash util.Uint256) (*block.Header, error)
|
||||||
CurrentHeaderHash() util.Uint256
|
CurrentHeaderHash() util.Uint256
|
||||||
|
@ -36,7 +36,7 @@ type Blockchainer interface {
|
||||||
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
||||||
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
||||||
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
||||||
GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error)
|
GetValidators() ([]*keys.PublicKey, error)
|
||||||
GetStandByValidators() (keys.PublicKeys, error)
|
GetStandByValidators() (keys.PublicKeys, error)
|
||||||
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
||||||
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +19,6 @@ type DAO interface {
|
||||||
AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error)
|
AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error)
|
||||||
DeleteContractState(hash util.Uint160) error
|
DeleteContractState(hash util.Uint160) error
|
||||||
DeleteStorageItem(scripthash util.Uint160, key []byte) error
|
DeleteStorageItem(scripthash util.Uint160, key []byte) error
|
||||||
DeleteValidatorState(vs *state.Validator) error
|
|
||||||
GetAccountState(hash util.Uint160) (*state.Account, error)
|
GetAccountState(hash util.Uint160) (*state.Account, error)
|
||||||
GetAccountStateOrNew(hash util.Uint160) (*state.Account, error)
|
GetAccountStateOrNew(hash util.Uint160) (*state.Account, error)
|
||||||
GetAndDecode(entity io.Serializable, key []byte) error
|
GetAndDecode(entity io.Serializable, key []byte) error
|
||||||
|
@ -39,9 +37,6 @@ type DAO interface {
|
||||||
GetStorageItemsWithPrefix(hash util.Uint160, prefix []byte) (map[string]*state.StorageItem, error)
|
GetStorageItemsWithPrefix(hash util.Uint160, prefix []byte) (map[string]*state.StorageItem, error)
|
||||||
GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error)
|
GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error)
|
||||||
GetUnspentCoinState(hash util.Uint256) (*state.UnspentCoin, error)
|
GetUnspentCoinState(hash util.Uint256) (*state.UnspentCoin, error)
|
||||||
GetValidatorState(publicKey *keys.PublicKey) (*state.Validator, error)
|
|
||||||
GetValidatorStateOrNew(publicKey *keys.PublicKey) (*state.Validator, error)
|
|
||||||
GetValidators() []*state.Validator
|
|
||||||
GetVersion() (string, error)
|
GetVersion() (string, error)
|
||||||
GetWrapped() DAO
|
GetWrapped() DAO
|
||||||
HasTransaction(hash util.Uint256) bool
|
HasTransaction(hash util.Uint256) bool
|
||||||
|
@ -57,7 +52,6 @@ type DAO interface {
|
||||||
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
|
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
|
||||||
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
|
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
|
||||||
PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) error
|
PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) error
|
||||||
PutValidatorState(vs *state.Validator) error
|
|
||||||
PutVersion(v string) error
|
PutVersion(v string) error
|
||||||
StoreAsBlock(block *block.Block, sysFee uint32) error
|
StoreAsBlock(block *block.Block, sysFee uint32) error
|
||||||
StoreAsCurrentBlock(block *block.Block) error
|
StoreAsCurrentBlock(block *block.Block) error
|
||||||
|
@ -307,61 +301,6 @@ func (dao *Simple) putUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin
|
||||||
|
|
||||||
// -- end unspent coins.
|
// -- end unspent coins.
|
||||||
|
|
||||||
// -- start validator.
|
|
||||||
|
|
||||||
// GetValidatorStateOrNew gets validator from store or created new one in case of error.
|
|
||||||
func (dao *Simple) GetValidatorStateOrNew(publicKey *keys.PublicKey) (*state.Validator, error) {
|
|
||||||
validatorState, err := dao.GetValidatorState(publicKey)
|
|
||||||
if err != nil {
|
|
||||||
if err != storage.ErrKeyNotFound {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
validatorState = &state.Validator{PublicKey: publicKey}
|
|
||||||
}
|
|
||||||
return validatorState, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValidators returns all validators from store.
|
|
||||||
func (dao *Simple) GetValidators() []*state.Validator {
|
|
||||||
var validators []*state.Validator
|
|
||||||
dao.Store.Seek(storage.STValidator.Bytes(), func(k, v []byte) {
|
|
||||||
r := io.NewBinReaderFromBuf(v)
|
|
||||||
validator := &state.Validator{}
|
|
||||||
validator.DecodeBinary(r)
|
|
||||||
if r.Err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
validators = append(validators, validator)
|
|
||||||
})
|
|
||||||
return validators
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValidatorState returns validator by publicKey.
|
|
||||||
func (dao *Simple) GetValidatorState(publicKey *keys.PublicKey) (*state.Validator, error) {
|
|
||||||
validatorState := &state.Validator{}
|
|
||||||
key := storage.AppendPrefix(storage.STValidator, publicKey.Bytes())
|
|
||||||
err := dao.GetAndDecode(validatorState, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return validatorState, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutValidatorState puts given Validator into the given store.
|
|
||||||
func (dao *Simple) PutValidatorState(vs *state.Validator) error {
|
|
||||||
key := storage.AppendPrefix(storage.STValidator, vs.PublicKey.Bytes())
|
|
||||||
return dao.Put(vs, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteValidatorState deletes given Validator into the given store.
|
|
||||||
func (dao *Simple) DeleteValidatorState(vs *state.Validator) error {
|
|
||||||
key := storage.AppendPrefix(storage.STValidator, vs.PublicKey.Bytes())
|
|
||||||
return dao.Store.Delete(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- end validator.
|
|
||||||
|
|
||||||
// -- start notification event.
|
// -- start notification event.
|
||||||
|
|
||||||
// GetAppExecResult gets application execution result from the
|
// GetAppExecResult gets application execution result from the
|
||||||
|
|
|
@ -113,61 +113,6 @@ func TestPutGetUnspentCoinState(t *testing.T) {
|
||||||
require.Equal(t, unspentCoinState, gotUnspentCoinState)
|
require.Equal(t, unspentCoinState, gotUnspentCoinState)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetValidatorStateOrNew_New(t *testing.T) {
|
|
||||||
dao := NewSimple(storage.NewMemoryStore())
|
|
||||||
publicKey := &keys.PublicKey{}
|
|
||||||
validatorState, err := dao.GetValidatorStateOrNew(publicKey)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, validatorState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutGetValidatorState(t *testing.T) {
|
|
||||||
dao := NewSimple(storage.NewMemoryStore())
|
|
||||||
publicKey := &keys.PublicKey{}
|
|
||||||
validatorState := &state.Validator{
|
|
||||||
PublicKey: publicKey,
|
|
||||||
Registered: false,
|
|
||||||
Votes: 0,
|
|
||||||
}
|
|
||||||
err := dao.PutValidatorState(validatorState)
|
|
||||||
require.NoError(t, err)
|
|
||||||
gotValidatorState, err := dao.GetValidatorState(publicKey)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, validatorState, gotValidatorState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteValidatorState(t *testing.T) {
|
|
||||||
dao := NewSimple(storage.NewMemoryStore())
|
|
||||||
publicKey := &keys.PublicKey{}
|
|
||||||
validatorState := &state.Validator{
|
|
||||||
PublicKey: publicKey,
|
|
||||||
Registered: false,
|
|
||||||
Votes: 0,
|
|
||||||
}
|
|
||||||
err := dao.PutValidatorState(validatorState)
|
|
||||||
require.NoError(t, err)
|
|
||||||
err = dao.DeleteValidatorState(validatorState)
|
|
||||||
require.NoError(t, err)
|
|
||||||
gotValidatorState, err := dao.GetValidatorState(publicKey)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Nil(t, gotValidatorState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetValidators(t *testing.T) {
|
|
||||||
dao := NewSimple(storage.NewMemoryStore())
|
|
||||||
publicKey := &keys.PublicKey{}
|
|
||||||
validatorState := &state.Validator{
|
|
||||||
PublicKey: publicKey,
|
|
||||||
Registered: false,
|
|
||||||
Votes: 0,
|
|
||||||
}
|
|
||||||
err := dao.PutValidatorState(validatorState)
|
|
||||||
require.NoError(t, err)
|
|
||||||
validators := dao.GetValidators()
|
|
||||||
require.Equal(t, validatorState, validators[0])
|
|
||||||
require.Len(t, validators, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutGetAppExecResult(t *testing.T) {
|
func TestPutGetAppExecResult(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore())
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
hash := random.Uint256()
|
hash := random.Uint256()
|
||||||
|
|
|
@ -236,13 +236,6 @@ func witnessGetVerificationScript(ic *interop.Context, v *vm.VM) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// bcGetValidators returns validators.
|
|
||||||
func bcGetValidators(ic *interop.Context, v *vm.VM) error {
|
|
||||||
validators := ic.DAO.GetValidators()
|
|
||||||
v.Estack().PushVal(validators)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// popInputFromVM returns transaction.Input from the first estack element.
|
// popInputFromVM returns transaction.Input from the first estack element.
|
||||||
func popInputFromVM(v *vm.VM) (*transaction.Input, error) {
|
func popInputFromVM(v *vm.VM) (*transaction.Input, error) {
|
||||||
inInterface := v.Estack().Pop().Value()
|
inInterface := v.Estack().Pop().Value()
|
||||||
|
|
|
@ -139,7 +139,6 @@ var neoInterops = []interop.Function{
|
||||||
{Name: "Neo.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
{Name: "Neo.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
||||||
{Name: "Neo.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 100},
|
{Name: "Neo.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 100},
|
||||||
{Name: "Neo.Blockchain.GetTransactionHeight", Func: bcGetTransactionHeight, Price: 100},
|
{Name: "Neo.Blockchain.GetTransactionHeight", Func: bcGetTransactionHeight, Price: 100},
|
||||||
{Name: "Neo.Blockchain.GetValidators", Func: bcGetValidators, Price: 200},
|
|
||||||
{Name: "Neo.Contract.Create", Func: contractCreate, Price: 0},
|
{Name: "Neo.Contract.Create", Func: contractCreate, Price: 0},
|
||||||
{Name: "Neo.Contract.Destroy", Func: contractDestroy, Price: 1},
|
{Name: "Neo.Contract.Destroy", Func: contractDestroy, Price: 1},
|
||||||
{Name: "Neo.Contract.GetScript", Func: contractGetScript, Price: 1},
|
{Name: "Neo.Contract.GetScript", Func: contractGetScript, Price: 1},
|
||||||
|
@ -225,7 +224,6 @@ var neoInterops = []interop.Function{
|
||||||
{Name: "AntShares.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
{Name: "AntShares.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
||||||
{Name: "AntShares.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
{Name: "AntShares.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
||||||
{Name: "AntShares.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 100},
|
{Name: "AntShares.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 100},
|
||||||
{Name: "AntShares.Blockchain.GetValidators", Func: bcGetValidators, Price: 200},
|
|
||||||
{Name: "AntShares.Contract.Create", Func: contractCreate, Price: 0},
|
{Name: "AntShares.Contract.Create", Func: contractCreate, Price: 0},
|
||||||
{Name: "AntShares.Contract.Destroy", Func: contractDestroy, Price: 1},
|
{Name: "AntShares.Contract.Destroy", Func: contractDestroy, Price: 1},
|
||||||
{Name: "AntShares.Contract.GetScript", Func: contractGetScript, Price: 1},
|
{Name: "AntShares.Contract.GetScript", Func: contractGetScript, Price: 1},
|
||||||
|
|
|
@ -31,12 +31,6 @@ type keyWithVotes struct {
|
||||||
Votes *big.Int
|
Votes *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// pkeyWithVotes is a deserialized key with votes balance.
|
|
||||||
type pkeyWithVotes struct {
|
|
||||||
Key *keys.PublicKey
|
|
||||||
Votes *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
neoSyscallName = "Neo.Native.Tokens.NEO"
|
neoSyscallName = "Neo.Native.Tokens.NEO"
|
||||||
// NEOTotalSupply is the total amount of NEO in the system.
|
// NEOTotalSupply is the total amount of NEO in the system.
|
||||||
|
@ -349,6 +343,24 @@ func (n *NEO) getRegisteredValidators(d dao.DAO) ([]keyWithVotes, error) {
|
||||||
return arr, nil
|
return arr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRegisteredValidators returns current registered validators list with keys
|
||||||
|
// and votes.
|
||||||
|
func (n *NEO) GetRegisteredValidators(d dao.DAO) ([]state.Validator, error) {
|
||||||
|
kvs, err := n.getRegisteredValidators(d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arr := make([]state.Validator, len(kvs))
|
||||||
|
for i := range kvs {
|
||||||
|
arr[i].Key, err = keys.NewPublicKeyFromBytes([]byte(kvs[i].Key))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arr[i].Votes = kvs[i].Votes
|
||||||
|
}
|
||||||
|
return arr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (n *NEO) getRegisteredValidatorsCall(ic *interop.Context, _ []vm.StackItem) vm.StackItem {
|
func (n *NEO) getRegisteredValidatorsCall(ic *interop.Context, _ []vm.StackItem) vm.StackItem {
|
||||||
validators, err := n.getRegisteredValidators(ic.DAO)
|
validators, err := n.getRegisteredValidators(ic.DAO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -374,18 +386,10 @@ func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (ke
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
validatorsBytes, err := n.getRegisteredValidators(d)
|
validators, err := n.GetRegisteredValidators(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
validators := make([]pkeyWithVotes, len(validatorsBytes))
|
|
||||||
for i := range validatorsBytes {
|
|
||||||
validators[i].Key, err = keys.NewPublicKeyFromBytes([]byte(validatorsBytes[i].Key))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
validators[i].Votes = validatorsBytes[i].Votes
|
|
||||||
}
|
|
||||||
sort.Slice(validators, func(i, j int) bool {
|
sort.Slice(validators, func(i, j int) bool {
|
||||||
// The most-voted validators should end up in the front of the list.
|
// The most-voted validators should end up in the front of the list.
|
||||||
cmp := validators[i].Votes.Cmp(validators[j].Votes)
|
cmp := validators[i].Votes.Cmp(validators[j].Votes)
|
||||||
|
@ -446,7 +450,7 @@ func (n *NEO) getNextBlockValidators(ic *interop.Context, _ []vm.StackItem) vm.S
|
||||||
func (n *NEO) GetNextBlockValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
|
func (n *NEO) GetNextBlockValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
|
||||||
si := d.GetStorageItem(n.Hash, nextValidatorsKey)
|
si := d.GetStorageItem(n.Hash, nextValidatorsKey)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
return bc.GetStandByValidators()
|
return n.GetValidatorsInternal(bc, d)
|
||||||
}
|
}
|
||||||
pubs := keys.PublicKeys{}
|
pubs := keys.PublicKeys{}
|
||||||
err := pubs.DecodeBytes(si.Value)
|
err := pubs.DecodeBytes(si.Value)
|
||||||
|
|
|
@ -1,39 +1,13 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"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/io"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validator holds the state of a validator.
|
// Validator holds the state of a validator (its key and votes balance).
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
PublicKey *keys.PublicKey
|
Key *keys.PublicKey
|
||||||
Registered bool
|
Votes *big.Int
|
||||||
Votes util.Fixed8
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisteredAndHasVotes returns true or false whether Validator is registered and has votes.
|
|
||||||
func (vs *Validator) RegisteredAndHasVotes() bool {
|
|
||||||
return vs.Registered && vs.Votes > util.Fixed8(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnregisteredAndHasNoVotes returns true when Validator is not registered and has no votes.
|
|
||||||
func (vs *Validator) UnregisteredAndHasNoVotes() bool {
|
|
||||||
return !vs.Registered && vs.Votes == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeBinary encodes Validator to the given BinWriter.
|
|
||||||
func (vs *Validator) EncodeBinary(bw *io.BinWriter) {
|
|
||||||
vs.PublicKey.EncodeBinary(bw)
|
|
||||||
bw.WriteBool(vs.Registered)
|
|
||||||
vs.Votes.EncodeBinary(bw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeBinary decodes Validator from the given BinReader.
|
|
||||||
func (vs *Validator) DecodeBinary(reader *io.BinReader) {
|
|
||||||
vs.PublicKey = &keys.PublicKey{}
|
|
||||||
vs.PublicKey.DecodeBinary(reader)
|
|
||||||
vs.Registered = reader.ReadBool()
|
|
||||||
vs.Votes.DecodeBinary(reader)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestValidatorState_DecodeEncodeBinary(t *testing.T) {
|
|
||||||
state := &Validator{
|
|
||||||
PublicKey: &keys.PublicKey{},
|
|
||||||
Registered: false,
|
|
||||||
Votes: util.Fixed8(10),
|
|
||||||
}
|
|
||||||
|
|
||||||
testserdes.EncodeDecodeBinary(t, state, new(Validator))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegisteredAndHasVotes_Registered(t *testing.T) {
|
|
||||||
state := &Validator{
|
|
||||||
PublicKey: &keys.PublicKey{
|
|
||||||
X: big.NewInt(1),
|
|
||||||
Y: big.NewInt(1),
|
|
||||||
},
|
|
||||||
Registered: true,
|
|
||||||
Votes: 0,
|
|
||||||
}
|
|
||||||
require.False(t, state.RegisteredAndHasVotes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegisteredAndHasVotes_RegisteredWithVotes(t *testing.T) {
|
|
||||||
state := &Validator{
|
|
||||||
PublicKey: &keys.PublicKey{
|
|
||||||
X: big.NewInt(1),
|
|
||||||
Y: big.NewInt(1),
|
|
||||||
},
|
|
||||||
Registered: true,
|
|
||||||
Votes: 1,
|
|
||||||
}
|
|
||||||
require.True(t, state.RegisteredAndHasVotes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegisteredAndHasVotes_NotRegisteredWithVotes(t *testing.T) {
|
|
||||||
state := &Validator{
|
|
||||||
PublicKey: &keys.PublicKey{
|
|
||||||
X: big.NewInt(1),
|
|
||||||
Y: big.NewInt(1),
|
|
||||||
},
|
|
||||||
Registered: false,
|
|
||||||
Votes: 1,
|
|
||||||
}
|
|
||||||
require.False(t, state.RegisteredAndHasVotes())
|
|
||||||
}
|
|
|
@ -96,13 +96,13 @@ func (chain testChain) GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog {
|
||||||
func (chain testChain) GetNEP5Balances(util.Uint160) *state.NEP5Balances {
|
func (chain testChain) GetNEP5Balances(util.Uint160) *state.NEP5Balances {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetValidators(...*transaction.Transaction) ([]*keys.PublicKey, error) {
|
func (chain testChain) GetValidators() ([]*keys.PublicKey, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetStandByValidators() (keys.PublicKeys, error) {
|
func (chain testChain) GetStandByValidators() (keys.PublicKeys, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetEnrollments() ([]*state.Validator, error) {
|
func (chain testChain) GetEnrollments() ([]state.Validator, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error) {
|
func (chain testChain) GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error) {
|
||||||
|
|
|
@ -2,13 +2,12 @@ package result
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validator used for the representation of
|
// Validator used for the representation of
|
||||||
// state.Validator on the RPC Server.
|
// state.Validator on the RPC Server.
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
PublicKey keys.PublicKey `json:"publickey"`
|
PublicKey keys.PublicKey `json:"publickey"`
|
||||||
Votes util.Fixed8 `json:"votes"`
|
Votes int64 `json:"votes,string"`
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -815,9 +815,9 @@ func (s *Server) getValidators(_ request.Params) (interface{}, error) {
|
||||||
var res []result.Validator
|
var res []result.Validator
|
||||||
for _, v := range enrollments {
|
for _, v := range enrollments {
|
||||||
res = append(res, result.Validator{
|
res = append(res, result.Validator{
|
||||||
PublicKey: *v.PublicKey,
|
PublicKey: *v.Key,
|
||||||
Votes: v.Votes,
|
Votes: v.Votes.Int64(),
|
||||||
Active: validators.Contains(v.PublicKey),
|
Active: validators.Contains(v.Key),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
Loading…
Reference in a new issue