From 2f8e7e4d33d0c38cbd1310136f7a663942c3f640 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 23 Jun 2020 13:26:39 +0300 Subject: [PATCH] native: fix getvalidators to match C# implementation ValidatorsCount is not initialized at block 0 with C# node (the first voter initializes it) and until that initialization happens the standby validators list is being returned as is without sorting. Fixes state mismatch for the key ffffffff0e00000000000000000000000000000001 in the first blocks. It also affects tests as now the first validator is different and it receives the network fees. --- pkg/consensus/consensus_test.go | 7 +++---- pkg/core/helper_test.go | 2 +- pkg/core/native/native_neo.go | 36 ++++++++++++++++----------------- pkg/rpc/server/server_test.go | 15 +++++++++++++- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index 6ad040cc5..196bdd5cf 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -213,7 +213,7 @@ func newTestService(t *testing.T) *service { } func getTestValidator(i int) (*privateKey, *publicKey) { - key := testchain.PrivateKey(i) + key := testchain.PrivateKeyByID(i) return &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()} } @@ -241,9 +241,8 @@ func signTx(t *testing.T, feePerByte util.Fixed8, txs ...*transaction.Transactio validators := make([]*keys.PublicKey, 4) privNetKeys := make([]*keys.PrivateKey, 4) for i := 0; i < 4; i++ { - privateKey, publicKey := getTestValidator(i) - validators[i] = publicKey.PublicKey - privNetKeys[i] = privateKey.PrivateKey + privNetKeys[i] = testchain.PrivateKey(i) + validators[i] = privNetKeys[i].PublicKey() } rawScript, err := smartcontract.CreateMultiSigRedeemScript(3, validators) require.NoError(t, err) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index f7b840cc5..c27c1ec10 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -210,7 +210,7 @@ func TestCreateBasicChain(t *testing.T) { t.Logf("txMoveNeo: %s", txMoveNeo.Hash().StringLE()) t.Logf("txMoveGas: %s", txMoveGas.Hash().StringLE()) - require.Equal(t, util.Fixed8FromInt64(1000), bc.GetUtilityTokenBalance(priv0ScriptHash)) + require.True(t, util.Fixed8FromInt64(1000).CompareTo(bc.GetUtilityTokenBalance(priv0ScriptHash)) <= 0) // info for getblockheader rpc tests t.Logf("header hash: %s", b.Hash().StringLE()) buf := io.NewBufBinWriter() diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index e09481bc1..7a9c7513c 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -112,8 +112,6 @@ func NewNEO() *NEO { // Initialize initializes NEO contract. func (n *NEO) Initialize(ic *interop.Context) error { - var si state.StorageItem - if err := n.nep5TokenNative.Initialize(ic); err != nil { return err } @@ -122,11 +120,6 @@ func (n *NEO) Initialize(ic *interop.Context) error { return errors.New("already initialized") } - vc := new(ValidatorsCount) - si.Value = vc.Bytes() - if err := ic.DAO.PutStorageItem(n.ContractID, validatorsCountKey, &si); err != nil { - return err - } h, vs, err := getStandbyValidatorsHash(ic) if err != nil { return err @@ -284,13 +277,20 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public newPubs = append(newPubs, pub) } if lp, lv := len(newPubs), len(acc.Votes); lp != lv { - si := ic.DAO.GetStorageItem(n.ContractID, validatorsCountKey) + var si *state.StorageItem + var vc *ValidatorsCount + var err error + + si = ic.DAO.GetStorageItem(n.ContractID, validatorsCountKey) if si == nil { - return errors.New("validators count uninitialized") - } - vc, err := ValidatorsCountFromBytes(si.Value) - if err != nil { - return err + // The first voter. + si = new(state.StorageItem) + vc = new(ValidatorsCount) + } else { + vc, err = ValidatorsCountFromBytes(si.Value) + if err != nil { + return err + } } if lv > 0 { vc[lv-1].Sub(&vc[lv-1], &acc.Balance) @@ -384,9 +384,13 @@ func (n *NEO) getRegisteredValidatorsCall(ic *interop.Context, _ []stackitem.Ite // GetValidatorsInternal returns a list of current validators. func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) { + standByValidators, err := bc.GetStandByValidators() + if err != nil { + return nil, err + } si := d.GetStorageItem(n.ContractID, validatorsCountKey) if si == nil { - return nil, errors.New("validators count uninitialized") + return standByValidators, nil } validatorsCount, err := ValidatorsCountFromBytes(si.Value) if err != nil { @@ -407,10 +411,6 @@ func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (ke }) count := validatorsCount.GetWeightedAverage() - standByValidators, err := bc.GetStandByValidators() - if err != nil { - return nil, err - } if count < len(standByValidators) { count = len(standByValidators) } diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 14729e5ed..73dd0f226 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -147,7 +147,7 @@ var rpcTestCases = map[string][]rpcTestCase{ }, { Asset: e.chain.UtilityTokenHash(), - Amount: "923.96937740", + Amount: "924.01732700", LastUpdated: 6, }}, Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), @@ -259,6 +259,7 @@ var rpcTestCases = map[string][]rpcTestCase{ // take burned gas into account u := testchain.PrivateKeyByID(0).GetScriptHash() for i := 0; i <= int(e.chain.BlockHeight()); i++ { + var netFee util.Fixed8 h := e.chain.GetHeaderHash(i) b, err := e.chain.GetBlock(h) require.NoError(t, err) @@ -274,7 +275,19 @@ var rpcTestCases = map[string][]rpcTestCase{ TxHash: b.Hash(), }) } + netFee += b.Transactions[j].NetworkFee } + if i > 0 { + expected.Received = append(expected.Received, result.NEP5Transfer{ + Timestamp: b.Timestamp, + Asset: e.chain.UtilityTokenHash(), + Address: "", // minted from network fees. + Amount: amountToString(int64(netFee), 8), + Index: b.Index, + TxHash: b.Hash(), + }) + } + } require.Equal(t, expected.Address, res.Address) require.ElementsMatch(t, expected.Sent, res.Sent)