From b0c051b817c4e58df15c82b62f504afbbf20f6bd Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 27 Aug 2020 17:42:19 +0300 Subject: [PATCH 1/3] internal: extend committee for unit tests Committee should differ from the set of validators, to catch possible bugs during testing. --- config/protocol.unit_testnet.yml | 2 ++ pkg/internal/testchain/address.go | 58 +++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/config/protocol.unit_testnet.yml b/config/protocol.unit_testnet.yml index 94f465989..3970409b1 100644 --- a/config/protocol.unit_testnet.yml +++ b/config/protocol.unit_testnet.yml @@ -7,6 +7,8 @@ ProtocolConfiguration: - 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e - 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699 - 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62 + - 02c429b3ea1aa486cb2edfd6e99d8055c1f81f1a9206664e2c40a586d187257557 + - 02c4de32252c50fa171dbe25379e4e2d55cdc12f69e382c39f59a44573ecff2f9d ValidatorsCount: 4 SeedList: - 127.0.0.1:20334 diff --git a/pkg/internal/testchain/address.go b/pkg/internal/testchain/address.go index e3cd1ca0f..0ee8620a6 100644 --- a/pkg/internal/testchain/address.go +++ b/pkg/internal/testchain/address.go @@ -23,18 +23,31 @@ var privNetKeys = []string{ "KzgWE3u3EDp13XPXXuTKZxeJ3Gi8Bsm8f9ijY3ZsCKKRvZUo1Cdn", "KxyjQ8eUa4FHt3Gvioyt1Wz29cTUrE4eTqX3yFSk1YFCsPL8uNsY", "L2oEXKRAAMiPEZukwR5ho2S6SMeQLhcK9mF71ZnF7GvT8dU4Kkgz", + + // Provide 2 committee extra members so that committee address differs from + // the validators one. + "L1Tr1iq5oz1jaFaMXP21sHDkJYDDkuLtpvQ4wRf1cjKvJYvnvpAb", + "Kz6XTUrExy78q8f4MjDHnwz8fYYyUE8iPXwPRAkHa3qN2JcHYm7e", } +// ValidatorsCount returns number of validators in the testchain. +const ValidatorsCount = 4 + var ( // ids maps validators order by public key sorting to validators ID. // which is an order of the validator in the StandByValidators list. - ids = []int{1, 3, 0, 2} + ids = []int{1, 3, 0, 2, 4, 5} // orders maps to validators id to it's order by public key sorting. - orders = []int{2, 0, 3, 1} + orders = []int{2, 0, 3, 1, 4, 5} ) // Size returns testchain initial validators amount. func Size() int { + return ValidatorsCount +} + +// CommitteeSize returns testchain committee size. +func CommitteeSize() int { return len(privNetKeys) } @@ -66,7 +79,7 @@ func PrivateKeyByID(id int) *keys.PrivateKey { // MultisigVerificationScript returns script hash of the consensus multisig address. func MultisigVerificationScript() []byte { var pubs keys.PublicKeys - for i := range privNetKeys { + for i := range privNetKeys[:ValidatorsCount] { priv := PrivateKey(ids[i]) pubs = append(pubs, priv.PublicKey()) } @@ -88,6 +101,31 @@ func MultisigAddress() string { return address.Uint160ToString(MultisigScriptHash()) } +// CommitteeVerificationScript returns script hash of the committee multisig address. +func CommitteeVerificationScript() []byte { + var pubs keys.PublicKeys + for i := range privNetKeys { + priv := PrivateKey(ids[i]) + pubs = append(pubs, priv.PublicKey()) + } + + script, err := smartcontract.CreateMajorityMultiSigRedeemScript(pubs) + if err != nil { + panic(err) + } + return script +} + +// CommitteeScriptHash returns committee address as Uint160. +func CommitteeScriptHash() util.Uint160 { + return hash.Hash160(CommitteeVerificationScript()) +} + +// CommitteeAddress return committee address as string. +func CommitteeAddress() string { + return address.Uint160ToString(CommitteeScriptHash()) +} + // Sign signs data by all consensus nodes and returns invocation script. func Sign(data []byte) []byte { buf := io.NewBufBinWriter() @@ -102,6 +140,20 @@ func Sign(data []byte) []byte { return buf.Bytes() } +// SignCommittee signs data by a majority of committee members. +func SignCommittee(data []byte) []byte { + buf := io.NewBufBinWriter() + for i := 0; i < CommitteeSize()/2+1; i++ { + pKey := PrivateKey(i) + sig := pKey.Sign(data) + if len(sig) != 64 { + panic("wrong signature length") + } + emit.Bytes(buf.BinWriter, sig) + } + return buf.Bytes() +} + // NewBlock creates new block for the given blockchain with the given offset // (usually, 1), primary node index and transactions. func NewBlock(t *testing.T, bc blockchainer.Blockchainer, offset uint32, primary uint32, txs ...*transaction.Transaction) *block.Block { From dce456f77ff2c10a754261778e9d44f9919bc8f5 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 27 Aug 2020 18:05:26 +0300 Subject: [PATCH 2/3] native: fix a bug in `GetCommitteeMembers` Return standby committee instead of validators. --- pkg/core/native/native_neo.go | 4 ++-- pkg/core/native_neo_test.go | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 5eb99da93..c8486d005 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -485,13 +485,13 @@ func (n *NEO) GetCommitteeMembers(bc blockchainer.Blockchainer, d dao.DAO) (keys votersCount.Mul(votersCount, big.NewInt(effectiveVoterTurnout)) voterTurnout := votersCount.Div(votersCount, n.getTotalSupply(d)) if voterTurnout.Sign() != 1 { - return bc.GetStandByValidators(), nil + return bc.GetStandByCommittee(), nil } cs, err := n.getCandidates(d) if err != nil { return nil, err } - sbVals := bc.GetStandByValidators() + sbVals := bc.GetStandByCommittee() count := len(sbVals) if len(cs) < count { return sbVals, nil diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go index 9cce25773..2fc60d29b 100644 --- a/pkg/core/native_neo_test.go +++ b/pkg/core/native_neo_test.go @@ -83,6 +83,11 @@ func TestNEO_Vote(t *testing.T) { ic.VM.Load(priv.PublicKey().GetVerificationScript()) require.NoError(t, neo.VoteInternal(ic, h, candidates[0])) + for i := testchain.ValidatorsCount; i < testchain.CommitteeSize(); i++ { + priv := testchain.PrivateKey(i) + require.NoError(t, neo.RegisterCandidateInternal(ic, priv.PublicKey())) + } + pubs, err = neo.GetValidatorsInternal(bc, ic.DAO) require.NoError(t, err) sortedCandidates := candidates.Copy() From 1788cf02a11596da90a26528b3ac48eae74ead9c Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 27 Aug 2020 18:17:15 +0300 Subject: [PATCH 3/3] core: fix VerifyTX test HighPriority attribute was lost during intermediate code changes. --- pkg/core/blockchain_test.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index b56ba8349..bf56275a6 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -17,7 +17,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/internal/testchain" "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" @@ -234,6 +233,9 @@ func TestVerifyTx(t *testing.T) { emit.Opcode(w.BinWriter, opcode.ASSERT) } } + emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer", + neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000)) + emit.Opcode(w.BinWriter, opcode.ASSERT) require.NoError(t, w.Err) txMove := bc.newTestTx(neoOwner, w.Bytes()) @@ -355,13 +357,13 @@ func TestVerifyTx(t *testing.T) { }) t.Run("ValidHighPriority", func(t *testing.T) { tx := bc.newTestTx(h, testScript) + tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.HighPriority}) tx.NetworkFee += 4_000_000 // multisig check tx.Signers = []transaction.Signer{{ - Account: testchain.MultisigScriptHash(), + Account: testchain.CommitteeScriptHash(), Scopes: transaction.FeeOnly, }} - validators := bc.GetStandByValidators() - rawScript, err := smartcontract.CreateMajorityMultiSigRedeemScript(validators) + rawScript := testchain.CommitteeVerificationScript() require.NoError(t, err) size := io.GetVarSize(tx) netFee, sizeDelta := CalculateNetworkFee(rawScript) @@ -369,7 +371,7 @@ func TestVerifyTx(t *testing.T) { tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() data := tx.GetSignedPart() tx.Scripts = []transaction.Witness{{ - InvocationScript: testchain.Sign(data), + InvocationScript: testchain.SignCommittee(data), VerificationScript: rawScript, }} require.NoError(t, bc.VerifyTx(tx))