diff options
Diffstat (limited to 'txnsync/txngroups_test.go')
-rw-r--r-- | txnsync/txngroups_test.go | 530 |
1 files changed, 0 insertions, 530 deletions
diff --git a/txnsync/txngroups_test.go b/txnsync/txngroups_test.go deleted file mode 100644 index 6306494f3..000000000 --- a/txnsync/txngroups_test.go +++ /dev/null @@ -1,530 +0,0 @@ -// Copyright (C) 2019-2021 Algorand, Inc. -// This file is part of go-algorand -// -// go-algorand is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// go-algorand is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with go-algorand. If not, see <https://www.gnu.org/licenses/>. - -package txnsync - -import ( - "context" - "database/sql" - "flag" - "io" - "io/ioutil" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/algorand/go-algorand/crypto" - "github.com/algorand/go-algorand/data/basics" - "github.com/algorand/go-algorand/data/bookkeeping" - "github.com/algorand/go-algorand/data/pooldata" - "github.com/algorand/go-algorand/data/transactions" - "github.com/algorand/go-algorand/ledger/ledgercore" - "github.com/algorand/go-algorand/protocol" - "github.com/algorand/go-algorand/rpcs" - "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/go-algorand/util/db" -) - -var blockDBFilename = flag.String("db", "", "Location of block db") -var startRound = flag.Int("start", 0, "Starting round") -var endRound = flag.Int("end", 10, "Ending round") - -func TestNibble(t *testing.T) { - partitiontest.PartitionTest(t) - - var b []byte - for i := 0; i < 10; i++ { - b = append(b, byte(i)) - } - compactNibblesArray(&b) - for i := 0; i < 10; i++ { - val, err := getNibble(b, i) - require.NoError(t, err) - require.Equal(t, byte(i), val) - } -} - -// old encoding method -func encodeTransactionGroupsOld(inTxnGroups []pooldata.SignedTxGroup) []byte { - stub := txGroupsEncodingStubOld{ - TxnGroups: make([]txnGroups, len(inTxnGroups)), - } - for i := range inTxnGroups { - stub.TxnGroups[i] = txnGroups(inTxnGroups[i].Transactions) - } - - return stub.MarshalMsg(protocol.GetEncodingBuf()[:0]) -} - -// old decoding method -func decodeTransactionGroupsOld(bytes []byte) (txnGroups []pooldata.SignedTxGroup, err error) { - if len(bytes) == 0 { - return nil, nil - } - var stub txGroupsEncodingStubOld - _, err = stub.UnmarshalMsg(bytes) - if err != nil { - return nil, err - } - txnGroups = make([]pooldata.SignedTxGroup, len(stub.TxnGroups)) - for i := range stub.TxnGroups { - txnGroups[i].Transactions = pooldata.SignedTxnSlice(stub.TxnGroups[i]) - } - return txnGroups, nil -} - -func TestTxnGroupEncodingSmall(t *testing.T) { - partitiontest.PartitionTest(t) - - genesisHash := crypto.Hash([]byte("gh")) - genesisID := "gID" - - inTxnGroups := []pooldata.SignedTxGroup{ - pooldata.SignedTxGroup{ - Transactions: []transactions.SignedTxn{ - { - Txn: transactions.Transaction{ - Type: protocol.PaymentTx, - Header: transactions.Header{ - Sender: basics.Address(crypto.Hash([]byte("2"))), - Fee: basics.MicroAlgos{Raw: 100}, - GenesisHash: genesisHash, - }, - PaymentTxnFields: transactions.PaymentTxnFields{ - Receiver: basics.Address(crypto.Hash([]byte("4"))), - Amount: basics.MicroAlgos{Raw: 1000}, - }, - }, - Sig: crypto.Signature{1}, - }, - }, - }, - pooldata.SignedTxGroup{ - Transactions: []transactions.SignedTxn{ - { - Txn: transactions.Transaction{ - Type: protocol.PaymentTx, - Header: transactions.Header{ - Sender: basics.Address(crypto.Hash([]byte("1"))), - Fee: basics.MicroAlgos{Raw: 100}, - GenesisHash: genesisHash, - GenesisID: genesisID, - }, - PaymentTxnFields: transactions.PaymentTxnFields{ - Receiver: basics.Address(crypto.Hash([]byte("2"))), - Amount: basics.MicroAlgos{Raw: 1000}, - }, - }, - Sig: crypto.Signature{2}, - }, - { - Txn: transactions.Transaction{ - Type: protocol.KeyRegistrationTx, - Header: transactions.Header{ - Sender: basics.Address(crypto.Hash([]byte("1"))), - GenesisHash: genesisHash, - GenesisID: genesisID, - }, - }, - Sig: crypto.Signature{3}, - }, - }, - }, - pooldata.SignedTxGroup{ - Transactions: []transactions.SignedTxn{ - { - Txn: transactions.Transaction{ - Type: protocol.AssetConfigTx, - Header: transactions.Header{ - Sender: basics.Address(crypto.Hash([]byte("1"))), - Fee: basics.MicroAlgos{Raw: 100}, - GenesisHash: genesisHash, - }, - }, - Sig: crypto.Signature{4}, - }, - { - Txn: transactions.Transaction{ - Type: protocol.AssetFreezeTx, - Header: transactions.Header{ - Sender: basics.Address(crypto.Hash([]byte("1"))), - GenesisHash: genesisHash, - }, - }, - Sig: crypto.Signature{5}, - }, - { - Txn: transactions.Transaction{ - Type: protocol.CompactCertTx, - Header: transactions.Header{ - Sender: basics.Address(crypto.Hash([]byte("1"))), - GenesisHash: genesisHash, - }, - }, - Msig: crypto.MultisigSig{Version: 1}, - }, - }, - }, - } - err := addGroupHashes(inTxnGroups, 6, []byte{1}) - require.NoError(t, err) - var s syncState - ptg, err := s.encodeTransactionGroups(inTxnGroups, 1000000000) - require.NoError(t, err) - require.Equal(t, ptg.CompressionFormat, compressionFormatNone) - out, err := decodeTransactionGroups(ptg, genesisID, genesisHash) - require.NoError(t, err) - require.ElementsMatch(t, inTxnGroups, out) -} - -// txnGroupsData fetches a sample dataset of txns, specify numBlocks up to 969 -func txnGroupsData(numBlocks int) (txnGroups []pooldata.SignedTxGroup, genesisID string, genesisHash crypto.Digest, err error) { - dat, err := ioutil.ReadFile("../test/testdata/mainnetblocks") - if err != nil { - return - } - dec := protocol.NewDecoderBytes(dat) - blocksData := make([]rpcs.EncodedBlockCert, numBlocks) - for i := 0; i < len(blocksData); i++ { - err = dec.Decode(&blocksData[i]) - if err == io.EOF { - break - } - if err != nil { - return - } - } - - for _, blockData := range blocksData { - block := blockData.Block - genesisID = block.GenesisID() - genesisHash = block.GenesisHash() - var payset [][]transactions.SignedTxnWithAD - payset, err = block.DecodePaysetGroups() - if err != nil { - return - } - for _, txns := range payset { - var txnGroup pooldata.SignedTxGroup - for _, txn := range txns { - txnGroup.Transactions = append(txnGroup.Transactions, txn.SignedTxn) - } - txnGroups = append(txnGroups, txnGroup) - } - } - return -} - -func TestTxnGroupEncodingLarge(t *testing.T) { - partitiontest.PartitionTest(t) - - txnGroups, genesisID, genesisHash, err := txnGroupsData(969) - require.NoError(t, err) - - var s syncState - ptg, err := s.encodeTransactionGroups(txnGroups, 0) - require.NoError(t, err) - require.Equal(t, ptg.CompressionFormat, compressionFormatDeflate) - out, err := decodeTransactionGroups(ptg, genesisID, genesisHash) - require.NoError(t, err) - require.ElementsMatch(t, txnGroups, out) - - encodedGroupsBytes := encodeTransactionGroupsOld(txnGroups) - out, err = decodeTransactionGroupsOld(encodedGroupsBytes) - require.NoError(t, err) - require.ElementsMatch(t, txnGroups, out) - - // check dataset - count := make(map[protocol.TxType]int) - sigs := 0 - msigs := 0 - lsigs := 0 - for _, txg := range txnGroups { - for _, txn := range txg.Transactions { - count[txn.Txn.Type]++ - if !txn.Sig.MsgIsZero() { - sigs++ - } - if !txn.Msig.MsgIsZero() { - msigs++ - } - if !txn.Lsig.MsgIsZero() { - lsigs++ - } - } - } - require.Equal(t, 2, len(count)) - require.Equal(t, 18351, count["axfer"]) - require.Equal(t, 1663, count["pay"]) - require.Equal(t, 20005, sigs) - require.Equal(t, 9, msigs) - require.Equal(t, 0, lsigs) -} - -func BenchmarkTxnGroupEncoding(b *testing.B) { - txnGroups, _, _, err := txnGroupsData(4) - require.NoError(b, err) - var size int - var s syncState - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - ptg, err := s.encodeTransactionGroups(txnGroups, 1000000000) - require.NoError(b, err) - size = len(ptg.Bytes) - releaseEncodedTransactionGroups(ptg.Bytes) - } - - b.ReportMetric(float64(size), "encodedDataBytes") -} - -func BenchmarkTxnGroupCompression(b *testing.B) { - txnGroups, _, _, err := txnGroupsData(4) - require.NoError(b, err) - var size int - var s syncState - ptg, err := s.encodeTransactionGroups(txnGroups, 1000000000) - require.NoError(b, err) - require.Equal(b, ptg.CompressionFormat, compressionFormatNone) - - b.ReportAllocs() - b.ResetTimer() - loopStartTime := time.Now() - for i := 0; i < b.N; i++ { - compressedGroupBytes, compressionFormat := s.compressTransactionGroupsBytes(ptg.Bytes) - require.Equal(b, compressionFormat, compressionFormatDeflate) - size = len(compressedGroupBytes) - } - loopDuration := time.Since(loopStartTime) - b.StopTimer() - b.ReportMetric(float64(len(ptg.Bytes)*b.N)/loopDuration.Seconds(), "estimatedGzipCompressionSpeed") - b.ReportMetric(float64(len(ptg.Bytes)-size)/float64(len(ptg.Bytes)), "estimatedGzipCompressionGains") -} - -func BenchmarkTxnGroupDecoding(b *testing.B) { - txnGroups, genesisID, genesisHash, err := txnGroupsData(4) - require.NoError(b, err) - - var s syncState - ptg, err := s.encodeTransactionGroups(txnGroups, 1000000000) - require.NoError(b, err) - require.Equal(b, ptg.CompressionFormat, compressionFormatNone) - require.NoError(b, err) - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err = decodeTransactionGroups(ptg, genesisID, genesisHash) - require.NoError(b, err) - } -} - -func BenchmarkTxnGroupDecompression(b *testing.B) { - txnGroups, _, _, err := txnGroupsData(4) - require.NoError(b, err) - - var s syncState - ptg, err := s.encodeTransactionGroups(txnGroups, 0) - require.NoError(b, err) - require.Equal(b, ptg.CompressionFormat, compressionFormatDeflate) - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err = decompressTransactionGroupsBytes(ptg.Bytes, ptg.LenDecompressedBytes) - require.NoError(b, err) - } -} - -func BenchmarkTxnGroupEncodingOld(b *testing.B) { - txnGroups, _, _, err := txnGroupsData(4) - require.NoError(b, err) - var encodedGroupsBytes []byte - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - encodedGroupsBytes = encodeTransactionGroupsOld(txnGroups) - releaseEncodedTransactionGroups(encodedGroupsBytes) - } - - b.ReportMetric(float64(len(encodedGroupsBytes)), "encodedDataBytes") -} - -func BenchmarkTxnGroupDecodingOld(b *testing.B) { - txnGroups, _, _, err := txnGroupsData(4) - require.NoError(b, err) - - encodedGroupsBytes := encodeTransactionGroupsOld(txnGroups) - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err = decodeTransactionGroupsOld(encodedGroupsBytes) - require.NoError(b, err) - } -} - -// TestTxnGroupEncodingReflection generates random -// txns of each type using reflection -func TestTxnGroupEncodingReflection(t *testing.T) { - partitiontest.PartitionTest(t) - - for i := 0; i < 10; i++ { - v0, err := protocol.RandomizeObject(&transactions.SignedTxn{}) - require.NoError(t, err) - stx, ok := v0.(*transactions.SignedTxn) - require.True(t, ok) - - var txns []transactions.SignedTxn - for _, txType := range protocol.TxnTypes { - txn := *stx - txn.Txn.PaymentTxnFields = transactions.PaymentTxnFields{} - txn.Txn.KeyregTxnFields = transactions.KeyregTxnFields{} - txn.Txn.AssetConfigTxnFields = transactions.AssetConfigTxnFields{} - txn.Txn.AssetTransferTxnFields = transactions.AssetTransferTxnFields{} - txn.Txn.AssetFreezeTxnFields = transactions.AssetFreezeTxnFields{} - txn.Txn.ApplicationCallTxnFields = transactions.ApplicationCallTxnFields{} - txn.Txn.CompactCertTxnFields = transactions.CompactCertTxnFields{} - txn.Txn.Type = txType - txn.Lsig.Logic = []byte("logic") - switch i % 3 { - case 0: // only have normal sig - txn.Msig = crypto.MultisigSig{} - txn.Lsig = transactions.LogicSig{} - case 1: // only have multi sig - txn.Sig = crypto.Signature{} - txn.Lsig = transactions.LogicSig{} - case 2: // only have logic sig - txn.Msig = crypto.MultisigSig{} - txn.Sig = crypto.Signature{} - } - switch txType { - case protocol.UnknownTx: - continue - case protocol.PaymentTx: - v0, err := protocol.RandomizeObject(&txn.Txn.PaymentTxnFields) - require.NoError(t, err) - PaymentTxnFields, ok := v0.(*transactions.PaymentTxnFields) - require.True(t, ok) - txn.Txn.PaymentTxnFields = *PaymentTxnFields - case protocol.KeyRegistrationTx: - v0, err := protocol.RandomizeObject(&txn.Txn.KeyregTxnFields) - require.NoError(t, err) - KeyregTxnFields, ok := v0.(*transactions.KeyregTxnFields) - require.True(t, ok) - txn.Txn.KeyregTxnFields = *KeyregTxnFields - case protocol.AssetConfigTx: - v0, err := protocol.RandomizeObject(&txn.Txn.AssetConfigTxnFields) - require.NoError(t, err) - AssetConfigTxnFields, ok := v0.(*transactions.AssetConfigTxnFields) - require.True(t, ok) - txn.Txn.AssetConfigTxnFields = *AssetConfigTxnFields - case protocol.AssetTransferTx: - v0, err := protocol.RandomizeObject(&txn.Txn.AssetTransferTxnFields) - require.NoError(t, err) - AssetTransferTxnFields, ok := v0.(*transactions.AssetTransferTxnFields) - require.True(t, ok) - txn.Txn.AssetTransferTxnFields = *AssetTransferTxnFields - case protocol.AssetFreezeTx: - v0, err := protocol.RandomizeObject(&txn.Txn.AssetFreezeTxnFields) - require.NoError(t, err) - AssetFreezeTxnFields, ok := v0.(*transactions.AssetFreezeTxnFields) - require.True(t, ok) - txn.Txn.AssetFreezeTxnFields = *AssetFreezeTxnFields - case protocol.ApplicationCallTx: - v0, err := protocol.RandomizeObject(&txn.Txn.ApplicationCallTxnFields) - require.NoError(t, err) - ApplicationCallTxnFields, ok := v0.(*transactions.ApplicationCallTxnFields) - require.True(t, ok) - txn.Txn.ApplicationCallTxnFields = *ApplicationCallTxnFields - txn.Txn.ApplicationCallTxnFields.OnCompletion = 1 - case protocol.CompactCertTx: - v0, err := protocol.RandomizeObject(&txn.Txn.CompactCertTxnFields) - require.NoError(t, err) - CompactCertTxnFields, ok := v0.(*transactions.CompactCertTxnFields) - require.True(t, ok) - txn.Txn.CompactCertTxnFields = *CompactCertTxnFields - default: - require.Fail(t, "unsupported txntype for txnsync msg encoding") - } - txn.Txn.Group = crypto.Digest{} - txns = append(txns, txn) - } - txnGroups := []pooldata.SignedTxGroup{ - pooldata.SignedTxGroup{ - Transactions: txns, - }, - } - err = addGroupHashes(txnGroups, len(txns), []byte{1}) - require.NoError(t, err) - var s syncState - ptg, err := s.encodeTransactionGroups(txnGroups, 0) - require.NoError(t, err) - out, err := decodeTransactionGroups(ptg, stx.Txn.GenesisID, stx.Txn.GenesisHash) - require.NoError(t, err) - require.ElementsMatch(t, txnGroups, out) - } -} - -// pass in flag -db to specify db, start round, end round -func TestTxnGroupEncodingArchival(t *testing.T) { - partitiontest.PartitionTest(t) - - if *blockDBFilename == "" { - t.Skip("no archival node db was provided") - } - blockDBs, err := db.OpenPair(*blockDBFilename, false) - require.NoError(t, err) - for r := basics.Round(*startRound); r < basics.Round(*endRound); r++ { - var block bookkeeping.Block - err = blockDBs.Rdb.Atomic(func(ctx context.Context, tx *sql.Tx) error { - var buf []byte - err = tx.QueryRow("SELECT blkdata FROM blocks WHERE rnd=?", r).Scan(&buf) - if err != nil { - if err == sql.ErrNoRows { - err = ledgercore.ErrNoEntry{Round: r} - } - return err - } - return protocol.Decode(buf, &block) - }) - require.NoError(t, err) - - var txnGroups []pooldata.SignedTxGroup - genesisID := block.GenesisID() - genesisHash := block.GenesisHash() - var payset [][]transactions.SignedTxnWithAD - payset, err := block.DecodePaysetGroups() - require.NoError(t, err) - for _, txns := range payset { - var txnGroup pooldata.SignedTxGroup - for _, txn := range txns { - txnGroup.Transactions = append(txnGroup.Transactions, txn.SignedTxn) - } - txnGroups = append(txnGroups, txnGroup) - } - - var s syncState - ptg, err := s.encodeTransactionGroups(txnGroups, 0) - require.NoError(t, err) - out, err := decodeTransactionGroups(ptg, genesisID, genesisHash) - require.NoError(t, err) - require.ElementsMatch(t, txnGroups, out) - } -} |