From df2886ca8f1684b70013104ff14259f434578903 Mon Sep 17 00:00:00 2001 From: Makis Christou Date: Thu, 14 Dec 2023 10:20:04 +0200 Subject: [PATCH] Add tx package tests --- tx/clause_test.go | 66 +++++++++++++++++ tx/receipt_test.go | 42 +++++++++++ tx/transaction_test.go | 156 ++++++++++++++++++++++++++++++++++++++++ tx/transactions_test.go | 28 ++++++++ tx/work_eval_test.go | 51 +++++++++++++ 5 files changed, 343 insertions(+) create mode 100644 tx/clause_test.go create mode 100644 tx/transactions_test.go create mode 100644 tx/work_eval_test.go diff --git a/tx/clause_test.go b/tx/clause_test.go new file mode 100644 index 000000000..534e80025 --- /dev/null +++ b/tx/clause_test.go @@ -0,0 +1,66 @@ +package tx + +import ( + "math/big" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vechain/thor/thor" +) + +func TestClauseTo(t *testing.T) { + var toAddress thor.Address + copy(toAddress[:], []byte{0xde, 0xad, 0xbe, 0xef}) + + clause := &Clause{ + body: clauseBody{ + To: &toAddress, + }, + } + + result := clause.To() + + // The result should not be nil and should match the mock address + assert.NotNil(t, result) + assert.Equal(t, toAddress, *result) + + // Test the case where 'To' is nil + clause.body.To = nil + result = clause.To() + + // The result should be nil + assert.Nil(t, result) +} + +func TestClauseValue(t *testing.T) { + expectedValue := big.NewInt(100) // Mock value + + clause := &Clause{ + body: clauseBody{ + Value: expectedValue, + }, + } + + result := clause.Value() + + // The result should not be nil and should match the mock value + assert.NotNil(t, result) + assert.Equal(t, 0, expectedValue.Cmp(result)) +} + +func TestClauseData(t *testing.T) { + expectedData := []byte{0x01, 0x02, 0x03} // Mock data + + clause := &Clause{ + body: clauseBody{ + Data: expectedData, + }, + } + + result := clause.Data() + + // The result should not be nil and should match the mock data + assert.NotNil(t, result) + assert.True(t, reflect.DeepEqual(expectedData, result)) +} diff --git a/tx/receipt_test.go b/tx/receipt_test.go index 70bc9059f..c8e703f6c 100644 --- a/tx/receipt_test.go +++ b/tx/receipt_test.go @@ -7,11 +7,26 @@ package tx_test import ( "fmt" + "math/big" "testing" + "github.com/stretchr/testify/assert" + "github.com/vechain/thor/thor" . "github.com/vechain/thor/tx" ) +func getMockReceipt() Receipt { + receipt := Receipt{ + GasUsed: 1000, + GasPayer: thor.Address{}, + Paid: big.NewInt(100), + Reward: big.NewInt(50), + Reverted: false, + Outputs: []*Output{}, + } + return receipt +} + func TestReceipt(t *testing.T) { var rs Receipts fmt.Println(rs.RootHash()) @@ -19,3 +34,30 @@ func TestReceipt(t *testing.T) { var txs Transactions fmt.Println(txs.RootHash()) } + +func TestReceiptStructure(t *testing.T) { + + receipt := getMockReceipt() + + assert.Equal(t, uint64(1000), receipt.GasUsed) + assert.Equal(t, thor.Address{}, receipt.GasPayer) + assert.Equal(t, big.NewInt(100), receipt.Paid) + assert.Equal(t, big.NewInt(50), receipt.Reward) + assert.Equal(t, false, receipt.Reverted) + assert.Equal(t, []*Output{}, receipt.Outputs) + +} + +func TestEmptyRootHash(t *testing.T) { + + receipt1 := getMockReceipt() + receipt2 := getMockReceipt() + + receipts := Receipts{ + &receipt1, + &receipt2, + } + + rootHash := receipts.RootHash() + assert.NotEqual(t, thor.Bytes32{}, rootHash, "Root hash should not be empty") +} diff --git a/tx/transaction_test.go b/tx/transaction_test.go index aec96c8df..73c1234e8 100644 --- a/tx/transaction_test.go +++ b/tx/transaction_test.go @@ -13,10 +13,166 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" + "github.com/vechain/thor/metric" "github.com/vechain/thor/thor" "github.com/vechain/thor/tx" ) +func GetMockTx() tx.Transaction { + to, _ := thor.ParseAddress("0x7567d83b7b8d80addcb281a71d54fc7b3364ffed") + trx := new(tx.Builder).ChainTag(1). + BlockRef(tx.BlockRef{0, 0, 0, 0, 0xaa, 0xbb, 0xcc, 0xdd}). + Expiration(32). + Clause(tx.NewClause(&to).WithValue(big.NewInt(10000)).WithData([]byte{0, 0, 0, 0x60, 0x60, 0x60})). + Clause(tx.NewClause(&to).WithValue(big.NewInt(20000)).WithData([]byte{0, 0, 0, 0x60, 0x60, 0x60})). + GasPriceCoef(128). + Gas(21000). + DependsOn(nil). + Nonce(12345678).Build() + + return *trx +} + +func TestIsExpired(t *testing.T) { + tx := GetMockTx() + res := tx.IsExpired(10) + assert.Equal(t, res, false) +} + +func TestHash(t *testing.T) { + tx := GetMockTx() + res := tx.Hash() + assert.Equal(t, res, thor.Bytes32(thor.Bytes32{0x4b, 0xff, 0x70, 0x1, 0xfe, 0xc4, 0x2, 0x84, 0xd9, 0x3b, 0x4c, 0x45, 0x61, 0x7d, 0xc7, 0x41, 0xb9, 0xa8, 0x8e, 0xd5, 0x9d, 0xf, 0x1, 0xa3, 0x76, 0x39, 0x4c, 0x7b, 0xfe, 0xa6, 0xed, 0x24})) + +} + +func TestDependsOn(t *testing.T) { + tx := GetMockTx() + res := tx.DependsOn() + var expected *thor.Bytes32 = nil + assert.Equal(t, expected, res) +} + +func TestTestFeatures(t *testing.T) { + txx := GetMockTx() + supportedFeatures := tx.Features(1) + res := txx.TestFeatures(supportedFeatures) + assert.Equal(t, res, nil) + +} + +func TestToString(t *testing.T) { + tx := GetMockTx() // Ensure this mock transaction has all the necessary fields populated + + // Construct the expected string representation of the transaction + // This should match the format used in the String() method of the Transaction struct + // and should reflect the actual state of the mock transaction + expectedString := "\n\tTx(0x0000000000000000000000000000000000000000000000000000000000000000, 87 B)\n\tOrigin: N/A\n\tClauses: [\n\t\t(To:\t0x7567d83b7b8d80addcb281a71d54fc7b3364ffed\n\t\t Value:\t10000\n\t\t Data:\t0x000000606060) \n\t\t(To:\t0x7567d83b7b8d80addcb281a71d54fc7b3364ffed\n\t\t Value:\t20000\n\t\t Data:\t0x000000606060)]\n\tGasPriceCoef: 128\n\tGas: 21000\n\tChainTag: 1\n\tBlockRef: 0-aabbccdd\n\tExpiration: 32\n\tDependsOn: nil\n\tNonce: 12345678\n\tUnprovedWork: 0\n\tDelegator: N/A\n\tSignature: 0x\n" + + res := tx.String() + + // Use assert.Equal to compare the actual result with the expected string + assert.Equal(t, expectedString, res) +} + +func TestTxSize(t *testing.T) { + + tx := GetMockTx() + + size := tx.Size() + assert.Equal(t, size, metric.StorageSize(87)) +} + +func TestProvedWork(t *testing.T) { + // Mock the transaction + tx := GetMockTx() + + // Define a head block number + headBlockNum := uint32(20) + + // Mock getBlockID function + getBlockID := func(num uint32) (thor.Bytes32, error) { + return thor.Bytes32{}, nil + } + + // Call ProvedWork + provedWork, err := tx.ProvedWork(headBlockNum, getBlockID) + + // Check for errors + assert.NoError(t, err) + + expectedProvedWork := big.NewInt(0) + assert.Equal(t, expectedProvedWork, provedWork) +} + +func TestChainTag(t *testing.T) { + tx := GetMockTx() + res := tx.ChainTag() + assert.Equal(t, res, uint8(0x1)) +} + +func TestNonce(t *testing.T) { + tx := GetMockTx() + res := tx.Nonce() + assert.Equal(t, res, uint64(0xbc614e)) +} + +func TestOverallGasPrice(t *testing.T) { + // Mock or create a Transaction with necessary fields initialized + tx := GetMockTx() + + // Define test cases + testCases := []struct { + name string + baseGasPrice *big.Int + provedWork *big.Int + expectedOutput *big.Int + }{ + { + name: "Case 1: No proved work", + baseGasPrice: big.NewInt(1000), + provedWork: big.NewInt(0), + expectedOutput: big.NewInt(1501), + }, + { + name: "Case 1: Negative proved work", + baseGasPrice: big.NewInt(1000), + provedWork: big.NewInt(-100), + expectedOutput: big.NewInt(1501), + }, + } + + // Run test cases + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Call OverallGasPrice + result := tx.OverallGasPrice(tc.baseGasPrice, tc.provedWork) + + // Check the value of the result + if result.Cmp(tc.expectedOutput) != 0 { + t.Errorf("%s: expected %v, got %v", tc.name, tc.expectedOutput, result) + } + }) + } +} + +func TestEvaluateWork(t *testing.T) { + origin := thor.BytesToAddress([]byte("origin")) + tx := GetMockTx() + + // Returns a function + evaluate := tx.EvaluateWork(origin) + + // Test with a range of nonce values + for nonce := uint64(0); nonce < 10; nonce++ { + work := evaluate(nonce) + + // Basic Assertions + assert.NotNil(t, work) + assert.True(t, work.Cmp(big.NewInt(0)) > 0, "Work should be positive") + } +} + func TestTx(t *testing.T) { to, _ := thor.ParseAddress("0x7567d83b7b8d80addcb281a71d54fc7b3364ffed") trx := new(tx.Builder).ChainTag(1). diff --git a/tx/transactions_test.go b/tx/transactions_test.go new file mode 100644 index 000000000..2b89a7b39 --- /dev/null +++ b/tx/transactions_test.go @@ -0,0 +1,28 @@ +package tx_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vechain/thor/thor" + "github.com/vechain/thor/tx" +) + +func MockTransactions(n int) tx.Transactions { + txs := make(tx.Transactions, n) + for i := range txs { + mockTx := GetMockTx() + txs[i] = &mockTx + } + return txs +} + +func TestRootHash(t *testing.T) { + // Test empty transactions slice + emptyTxs := tx.Transactions{} + emptyRoot := emptyTxs.RootHash() + assert.Equal(t, emptyTxs.RootHash(), emptyRoot) + + nonEmptyTxs := MockTransactions(2) + assert.Equal(t, nonEmptyTxs.RootHash(), thor.Bytes32{0x30, 0x9a, 0xd5, 0x4b, 0x28, 0x76, 0x65, 0x52, 0x66, 0x89, 0x7b, 0x19, 0x22, 0x24, 0x63, 0xd8, 0x27, 0xc8, 0x2a, 0xd6, 0x20, 0x17, 0x7a, 0xcf, 0x9a, 0xfa, 0xc, 0xce, 0xff, 0x12, 0x24, 0x48}) +} diff --git a/tx/work_eval_test.go b/tx/work_eval_test.go new file mode 100644 index 000000000..01fef6bb1 --- /dev/null +++ b/tx/work_eval_test.go @@ -0,0 +1,51 @@ +package tx + +import ( + "math" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWorkToGas(t *testing.T) { + // Test cases + testCases := []struct { + name string + work *big.Int + blockNum uint32 + expected uint64 + }{ + { + name: "Basic conversion", + work: big.NewInt(10000), + blockNum: 100, + expected: 10, + }, + { + name: "Zero work", + work: big.NewInt(0), + blockNum: 100, + expected: 0, + }, + { + name: "Large work value", + work: big.NewInt(math.MaxInt64), + blockNum: 100, + expected: 0x20c49ba5e353f7, + }, + { + name: "Large work value and blockNum", + work: big.NewInt(math.MaxInt64), + blockNum: 12345679, + expected: 0x52fc533083329, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := workToGas(tc.work, tc.blockNum) + assert.Equal(t, tc.expected, result, "Expected and actual gas should match") + }) + } +}