From 98bb3f720180549b70fa35d492e9e900730fcdc5 Mon Sep 17 00:00:00 2001 From: Alexandros Hasikos Date: Mon, 8 Jan 2024 14:45:38 +0200 Subject: [PATCH] #34 Adds code coverage tests to packer --- packer/flow_test.go | 182 ++++++++++++++++++++++++++++++++++++++++++ packer/packer_test.go | 43 ++++++++++ 2 files changed, 225 insertions(+) create mode 100644 packer/flow_test.go diff --git a/packer/flow_test.go b/packer/flow_test.go new file mode 100644 index 000000000..1c88f9833 --- /dev/null +++ b/packer/flow_test.go @@ -0,0 +1,182 @@ +// Copyright (c) 2024 The VeChainThor developers + +// Distributed under the GNU Lesser General Public License v3.0 software license, see the accompanying +// file LICENSE or + +package packer_test + +import ( + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/vechain/thor/v2/builtin" + "github.com/vechain/thor/v2/chain" + "github.com/vechain/thor/v2/genesis" + "github.com/vechain/thor/v2/muxdb" + "github.com/vechain/thor/v2/packer" + "github.com/vechain/thor/v2/state" + "github.com/vechain/thor/v2/thor" + "github.com/vechain/thor/v2/tx" +) + +func createTx(chainTag byte, gasPriceCoef uint8, expiration uint32, gas uint64, nonce uint64, dependsOn *thor.Bytes32, clause *tx.Clause, br tx.BlockRef) *tx.Transaction { + builder := new(tx.Builder). + ChainTag(chainTag). + GasPriceCoef(gasPriceCoef). + Expiration(expiration). + Gas(gas). + Nonce(nonce). + DependsOn(dependsOn). + Clause(clause). + BlockRef(br) + + transaction := builder.Build() + + signature, _ := crypto.Sign(transaction.SigningHash().Bytes(), genesis.DevAccounts()[0].PrivateKey) + + return transaction.WithSignature(signature) +} + +func TestAdopt(t *testing.T) { + // Setup environment + db := muxdb.NewMem() + stater := state.NewStater(db) + g := genesis.NewDevnet() + + // Build genesis block + b, _, _, _ := g.Build(stater) + repo, _ := chain.NewRepository(db, b) + + // Common transaction setup + chainTag := repo.ChainTag() + addr := thor.BytesToAddress([]byte("to")) + clause := tx.NewClause(&addr).WithValue(big.NewInt(10000)) + + // Create and adopt two transactions + pkr := packer.New(repo, stater, genesis.DevAccounts()[0].Address, &genesis.DevAccounts()[0].Address, thor.NoFork) + sum, err := repo.GetBlockSummary(b.Header().ID()) + if err != nil { + t.Fatal("Error getting block summary:", err) + } + + flow, err := pkr.Schedule(sum, uint64(time.Now().Unix())) + if err != nil { + t.Fatal("Error scheduling:", err) + } + + tx1 := createTx(chainTag, 1, 10, 21000, 1, nil, clause, tx.NewBlockRef(0)) + if err := flow.Adopt(tx1); err != nil { + t.Fatal("Error adopting tx1:", err) + } + + tx2 := createTx(chainTag, 1, 10, 21000, 2, (*thor.Bytes32)(tx1.ID().Bytes()), clause, tx.NewBlockRef(0)) + if err := flow.Adopt(tx2); err != nil { + t.Fatal("Error adopting tx2:", err) + } + + //Repeat transaction + expectedErrorMessage := "known tx" + if err := flow.Adopt(tx2); err.Error() != expectedErrorMessage { + t.Fatalf("Expected error message: '%s', but got: '%s'", expectedErrorMessage, err.Error()) + } + + // Test dependency that does not exist + tx3 := createTx(chainTag, 1, 10, 21000, 2, (*thor.Bytes32)((thor.Bytes32{0x1}).Bytes()), clause, tx.NewBlockRef(0)) + expectedErrorMessage = "tx not adoptable now" + if err := flow.Adopt(tx3); err.Error() != expectedErrorMessage { + t.Fatalf("Expected error message: '%s', but got: '%s'", expectedErrorMessage, err.Error()) + } + + // Test Getters + flow.ParentHeader() + flow.When() + flow.TotalScore() +} + +func TestPack(t *testing.T) { + db := muxdb.NewMem() + g := genesis.NewDevnet() + + stater := state.NewStater(db) + parent, _, _, _ := g.Build(stater) + + repo, _ := chain.NewRepository(db, parent) + + forkConfig := thor.NoFork + forkConfig.BLOCKLIST = 0 + forkConfig.VIP214 = 0 + forkConfig.FINALITY = 0 + + proposer := genesis.DevAccounts()[0] + p := packer.New(repo, stater, proposer.Address, &proposer.Address, forkConfig) + parentSum, _ := repo.GetBlockSummary(parent.Header().ID()) + flow, _ := p.Schedule(parentSum, uint64(parent.Header().Timestamp()+100*thor.BlockInterval)) + + flow.Pack(proposer.PrivateKey, 0, false) + + //Test with shouldVote + flow.Pack(proposer.PrivateKey, 0, true) + + //Test wrong private key + expectedErrorMessage := "private key mismatch" + if _, _, _, err := flow.Pack(genesis.DevAccounts()[1].PrivateKey, 0, false); err.Error() != expectedErrorMessage { + t.Fatalf("Expected error message: '%s', but got: '%s'", expectedErrorMessage, err.Error()) + } +} + +func TestAdoptErr(t *testing.T) { + db := muxdb.NewMem() + stater := state.NewStater(db) + launchTime := uint64(1526400000) + g := new(genesis.Builder). + GasLimit(0). + Timestamp(launchTime). + State(func(state *state.State) error { + bal, _ := new(big.Int).SetString("1000000000000000000000000000", 10) + state.SetCode(builtin.Authority.Address, builtin.Authority.RuntimeBytecodes()) + builtin.Params.Native(state).Set(thor.KeyExecutorAddress, new(big.Int).SetBytes(genesis.DevAccounts()[0].Address[:])) + for _, acc := range genesis.DevAccounts() { + state.SetBalance(acc.Address, bal) + state.SetEnergy(acc.Address, bal, launchTime) + builtin.Authority.Native(state).Add(acc.Address, acc.Address, thor.Bytes32{}) + } + return nil + }) + + // Build genesis block + b, _, _, _ := g.Build(stater) + + repo, _ := chain.NewRepository(db, b) + + // Common transaction setup + addr := thor.BytesToAddress([]byte("to")) + clause := tx.NewClause(&addr).WithValue(big.NewInt(10000)) + + pkr := packer.New(repo, stater, genesis.DevAccounts()[0].Address, &genesis.DevAccounts()[0].Address, thor.NoFork) + sum, _ := repo.GetBlockSummary(b.Header().ID()) + + flow, _ := pkr.Schedule(sum, uint64(time.Now().Unix())) + + // Test chain tag mismatch + tx1 := createTx(byte(0xFF), 1, 10, 21000, 1, nil, clause, tx.NewBlockRef(0)) + expectedErrorMessage := "bad tx: chain tag mismatch" + if err := flow.Adopt(tx1); err.Error() != expectedErrorMessage { + t.Fatalf("Expected error message: '%s', but got: '%s'", expectedErrorMessage, err.Error()) + } + + // Test wrong block reference + tx2 := createTx(repo.ChainTag(), 1, 10, 1, 21000, nil, clause, tx.NewBlockRef(1000)) + expectedErrorMessage = "tx not adoptable now" + if err := flow.Adopt(tx2); err.Error() != expectedErrorMessage { + t.Fatalf("Expected error message: '%s', but got: '%s'", expectedErrorMessage, err.Error()) + } + + // Test exceeded gas limit + tx3 := createTx(repo.ChainTag(), 1, 0, 1, 1, nil, clause, tx.NewBlockRef(1)) + expectedErrorMessage = "gas limit reached" + if err := flow.Adopt(tx3); err.Error() != expectedErrorMessage { + t.Fatalf("Expected error message: '%s', but got: '%s'", expectedErrorMessage, err.Error()) + } +} diff --git a/packer/packer_test.go b/packer/packer_test.go index dc3188d44..a099a3d01 100644 --- a/packer/packer_test.go +++ b/packer/packer_test.go @@ -227,3 +227,46 @@ func TestBlocklist(t *testing.T) { t.Fatal("adopt tx from non-blocked origin should not return error") } } + +func TestMock(t *testing.T) { + db := muxdb.NewMem() + stater := state.NewStater(db) + g := genesis.NewDevnet() + + b0, _, _, _ := g.Build(stater) + repo, _ := chain.NewRepository(db, b0) + + a0 := genesis.DevAccounts()[0] + + p := packer.New(repo, stater, a0.Address, &a0.Address, thor.NoFork) + + best := repo.BestBlockSummary() + + // Create a packing flow mock with header gas limit + _, err := p.Mock(best, uint64(time.Now().Unix()), b0.Header().GasLimit()) + if err != nil { + t.Fatal("Failure to create a packing flow mock") + } + + // Create a packing flow mock with 0 gas limit + _, err = p.Mock(best, uint64(time.Now().Unix()), 0) + if err != nil { + t.Fatal("Failure to create a packing flow mock") + } +} + +func TestSetGasLimit(t *testing.T) { + db := muxdb.NewMem() + + g := genesis.NewDevnet() + stater := state.NewStater(db) + b0, _, _, _ := g.Build(stater) + repo, _ := chain.NewRepository(db, b0) + + a0 := genesis.DevAccounts()[0] + + p := packer.New(repo, stater, a0.Address, &a0.Address, thor.NoFork) + + // This is just for code coverage purposes. There is no getter function for targetGasLimit to test the function. + p.SetTargetGasLimit(0xFFFF) +}