From 6ede65610d82bd6e673f68039fad3612ea5bab8c Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Mar 2020 19:52:28 +0300 Subject: [PATCH 1/2] core: add appropriate hashes to check for State TX These checks are important for proper transaction verification. --- pkg/core/blockchain.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index e9a45d4f5..f180f7116 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1885,6 +1885,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)) From 77a799f7d00d0198573be70a33d646909f92bbb6 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Mar 2020 20:14:59 +0300 Subject: [PATCH 2/2] core: add missing state tx verifications --- pkg/core/blockchain.go | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index f180f7116..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)