diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index e9a45d4f5..2e9b9ce31 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1387,6 +1387,63 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e if inv.Gas.FractionalValue() != 0 { return errors.New("invocation gas can only be integer") } + case transaction.StateType: + stx := t.Data.(*transaction.StateTX) + for _, desc := range stx.Descriptors { + switch desc.Type { + case transaction.Account: + if desc.Field != "Votes" { + return errors.New("bad field in account descriptor") + } + votes := keys.PublicKeys{} + err := votes.DecodeBytes(desc.Value) + if err != nil { + return err + } + if len(votes) > state.MaxValidatorsVoted { + return errors.New("voting candidate limit exceeded") + } + hash, err := util.Uint160DecodeBytesBE(desc.Key) + if err != nil { + return err + } + account, err := bc.dao.GetAccountStateOrNew(hash) + if err != nil { + return err + } + if account.IsFrozen { + return errors.New("account is frozen") + } + if votes.Len() > 0 { + balance := account.GetBalanceValues()[GoverningTokenID()] + if balance == 0 { + return errors.New("no governing tokens available to vote") + } + validators, err := bc.GetEnrollments() + if err != nil { + return err + } + for _, k := range votes { + var isRegistered bool + for i := range validators { + if k.Equal(validators[i].PublicKey) { + isRegistered = true + break + } + } + if !isRegistered { + return errors.New("vote for unregistered validator") + } + } + } + case transaction.Validator: + if desc.Field != "Registered" { + return errors.New("bad field in validator descriptor") + } + default: + return errors.New("bad descriptor type") + } + } } return bc.verifyTxWitnesses(t, block) @@ -1885,6 +1942,31 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([ case transaction.EnrollmentType: etx := t.Data.(*transaction.EnrollmentTX) hashes[etx.PublicKey.GetScriptHash()] = true + case transaction.StateType: + stx := t.Data.(*transaction.StateTX) + for _, desc := range stx.Descriptors { + switch desc.Type { + case transaction.Account: + if desc.Field != "Votes" { + return nil, errors.New("bad account state descriptor") + } + hash, err := util.Uint160DecodeBytesBE(desc.Key) + if err != nil { + return nil, err + } + hashes[hash] = true + case transaction.Validator: + if desc.Field != "Registered" { + return nil, errors.New("bad validator state descriptor") + } + key := &keys.PublicKey{} + err := key.DecodeBytes(desc.Key) + if err != nil { + return nil, err + } + hashes[key.GetScriptHash()] = true + } + } } // convert hashes to []util.Uint160 hashesResult := make([]util.Uint160, 0, len(hashes))