From cce40587d229612d06e5890e3919cb51838b23d7 Mon Sep 17 00:00:00 2001 From: paologalligit Date: Fri, 20 Dec 2024 11:38:57 +0100 Subject: [PATCH] feat: differentiate legacy and dyn fee json response --- api/transactions/transactions_converter.go | 79 +++++++++++++++ .../transactions_coverter_test.go | 95 +++++++++++++++++++ api/transactions/transactions_test.go | 13 ++- api/transactions/types.go | 58 ----------- 4 files changed, 184 insertions(+), 61 deletions(-) create mode 100644 api/transactions/transactions_converter.go create mode 100644 api/transactions/transactions_coverter_test.go diff --git a/api/transactions/transactions_converter.go b/api/transactions/transactions_converter.go new file mode 100644 index 000000000..86a118d02 --- /dev/null +++ b/api/transactions/transactions_converter.go @@ -0,0 +1,79 @@ +// 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 transactions + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/vechain/thor/v2/block" + "github.com/vechain/thor/v2/thor" + "github.com/vechain/thor/v2/tx" +) + +type Transaction struct { + ID thor.Bytes32 `json:"id"` + ChainTag byte `json:"chainTag"` + BlockRef string `json:"blockRef"` + Expiration uint32 `json:"expiration"` + Clauses Clauses `json:"clauses"` + GasPriceCoef uint8 `json:"gasPriceCoef"` + Gas uint64 `json:"gas"` + MaxFeePerGas *big.Int `json:"maxFeePerGas,omitempty"` + MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas,omitempty"` + TxType math.HexOrDecimal64 `json:"txType"` + Origin thor.Address `json:"origin"` + Delegator *thor.Address `json:"delegator"` + Nonce math.HexOrDecimal64 `json:"nonce"` + DependsOn *thor.Bytes32 `json:"dependsOn"` + Size uint32 `json:"size"` + Meta *TxMeta `json:"meta"` +} + +// convertTransaction convert a raw transaction into a json format transaction +func convertTransaction(trx *tx.Transaction, header *block.Header) *Transaction { + //tx origin + origin, _ := trx.Origin() + delegator, _ := trx.Delegator() + + cls := make(Clauses, len(trx.Clauses())) + for i, c := range trx.Clauses() { + cls[i] = convertClause(c) + } + br := trx.BlockRef() + t := &Transaction{ + ChainTag: trx.ChainTag(), + TxType: math.HexOrDecimal64(trx.Type()), + ID: trx.ID(), + Origin: origin, + BlockRef: hexutil.Encode(br[:]), + Expiration: trx.Expiration(), + Nonce: math.HexOrDecimal64(trx.Nonce()), + Size: uint32(trx.Size()), + Gas: trx.Gas(), + DependsOn: trx.DependsOn(), + Clauses: cls, + Delegator: delegator, + } + + switch trx.Type() { + case tx.LegacyTxType: + t.GasPriceCoef = trx.GasPriceCoef() + default: + t.MaxFeePerGas = trx.MaxFeePerGas() + t.MaxPriorityFeePerGas = trx.MaxPriorityFeePerGas() + } + + if header != nil { + t.Meta = &TxMeta{ + BlockID: header.ID(), + BlockNumber: header.Number(), + BlockTimestamp: header.Timestamp(), + } + } + return t +} diff --git a/api/transactions/transactions_coverter_test.go b/api/transactions/transactions_coverter_test.go new file mode 100644 index 000000000..58f3cef7c --- /dev/null +++ b/api/transactions/transactions_coverter_test.go @@ -0,0 +1,95 @@ +// 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 transactions + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/assert" + "github.com/vechain/thor/v2/block" + "github.com/vechain/thor/v2/thor" + "github.com/vechain/thor/v2/tx" +) + +func TestConvertLegacyTransaction_Success(t *testing.T) { + addr := thor.BytesToAddress([]byte("to")) + cla := tx.NewClause(&addr).WithValue(big.NewInt(10000)) + cla2 := tx.NewClause(&addr).WithValue(big.NewInt(10000)) + br := tx.NewBlockRef(0) + transaction := new(tx.LegacyBuilder). + ChainTag(123). + GasPriceCoef(1). + Expiration(10). + Gas(37000). + Nonce(1). + Clause(cla). + Clause(cla2). + BlockRef(br). + Build() + + header := new(block.Builder).Build().Header() + + result := convertTransaction(transaction, header) + // Common fields + assert.Equal(t, hexutil.Encode(br[:]), result.BlockRef) + assert.Equal(t, transaction.ChainTag(), result.ChainTag) + assert.Equal(t, transaction.Expiration(), result.Expiration) + assert.Equal(t, transaction.Gas(), result.Gas) + assert.Equal(t, math.HexOrDecimal64(transaction.Nonce()), result.Nonce) + assert.Equal(t, 2, len(result.Clauses)) + assert.Equal(t, addr, *result.Clauses[0].To) + assert.Equal(t, convertClause(cla), result.Clauses[0]) + assert.Equal(t, addr, *result.Clauses[1].To) + assert.Equal(t, convertClause(cla2), result.Clauses[1]) + // Legacy fields + assert.Equal(t, uint8(1), result.GasPriceCoef) + // Non legacy fields + assert.Empty(t, result.MaxFeePerGas) + assert.Empty(t, result.MaxPriorityFeePerGas) +} + +func TestConvertDynTransaction_Success(t *testing.T) { + addr := thor.BytesToAddress([]byte("to")) + cla := tx.NewClause(&addr).WithValue(big.NewInt(10000)) + cla2 := tx.NewClause(&addr).WithValue(big.NewInt(10000)) + br := tx.NewBlockRef(0) + maxFeePerGas := big.NewInt(25000) + maxPriorityFeePerGas := big.NewInt(100) + transaction := new(tx.DynFeeBuilder). + ChainTag(123). + MaxFeePerGas(maxFeePerGas). + MaxPriorityFeePerGas(maxPriorityFeePerGas). + Expiration(10). + Gas(37000). + Nonce(1). + Clause(cla). + Clause(cla2). + BlockRef(br). + Build() + + header := new(block.Builder).Build().Header() + + result := convertTransaction(transaction, header) + // Common fields + assert.Equal(t, hexutil.Encode(br[:]), result.BlockRef) + assert.Equal(t, transaction.ChainTag(), result.ChainTag) + assert.Equal(t, transaction.Expiration(), result.Expiration) + assert.Equal(t, transaction.Gas(), result.Gas) + assert.Equal(t, math.HexOrDecimal64(transaction.Nonce()), result.Nonce) + assert.Equal(t, 2, len(result.Clauses)) + assert.Equal(t, addr, *result.Clauses[0].To) + assert.Equal(t, convertClause(cla), result.Clauses[0]) + assert.Equal(t, addr, *result.Clauses[1].To) + assert.Equal(t, convertClause(cla2), result.Clauses[1]) + // DynFee fields + assert.Equal(t, maxFeePerGas, result.MaxFeePerGas) + assert.Equal(t, maxPriorityFeePerGas, result.MaxPriorityFeePerGas) + // Non dynFee fields + assert.Empty(t, result.GasPriceCoef) +} diff --git a/api/transactions/transactions_test.go b/api/transactions/transactions_test.go index 56b54c092..40ec4f7f5 100644 --- a/api/transactions/transactions_test.go +++ b/api/transactions/transactions_test.go @@ -390,15 +390,22 @@ func checkMatchingTx(t *testing.T, expectedTx *tx.Transaction, actualTx *transac } assert.Equal(t, origin, actualTx.Origin) assert.Equal(t, expectedTx.ID(), actualTx.ID) - assert.Equal(t, expectedTx.GasPriceCoef(), actualTx.GasPriceCoef) - assert.Equal(t, expectedTx.MaxFeePerGas(), actualTx.MaxFeePerGas) - assert.Equal(t, expectedTx.MaxPriorityFeePerGas(), actualTx.MaxPriorityFeePerGas) assert.Equal(t, expectedTx.Gas(), actualTx.Gas) for i, c := range expectedTx.Clauses() { assert.Equal(t, hexutil.Encode(c.Data()), actualTx.Clauses[i].Data) assert.Equal(t, *c.Value(), big.Int(actualTx.Clauses[i].Value)) assert.Equal(t, c.To(), actualTx.Clauses[i].To) } + switch expectedTx.Type() { + case tx.LegacyTxType: + assert.Equal(t, expectedTx.GasPriceCoef(), actualTx.GasPriceCoef) + assert.Empty(t, actualTx.MaxFeePerGas) + assert.Empty(t, actualTx.MaxPriorityFeePerGas) + case tx.DynamicFeeTxType: + assert.Empty(t, actualTx.GasPriceCoef) + assert.Equal(t, expectedTx.MaxFeePerGas(), actualTx.MaxFeePerGas) + assert.Equal(t, expectedTx.MaxPriorityFeePerGas(), actualTx.MaxPriorityFeePerGas) + } } func httpGetAndCheckResponseStatus(t *testing.T, url string, responseStatusCode int) []byte { diff --git a/api/transactions/types.go b/api/transactions/types.go index 3e99ff251..c2f676ca4 100644 --- a/api/transactions/types.go +++ b/api/transactions/types.go @@ -7,7 +7,6 @@ package transactions import ( "fmt" - "math/big" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" @@ -45,25 +44,6 @@ func (c *Clause) String() string { c.Data) } -// Transaction transaction -type Transaction struct { - ID thor.Bytes32 `json:"id"` - ChainTag byte `json:"chainTag"` - BlockRef string `json:"blockRef"` - Expiration uint32 `json:"expiration"` - Clauses Clauses `json:"clauses"` - GasPriceCoef uint8 `json:"gasPriceCoef"` - Gas uint64 `json:"gas"` - MaxFeePerGas *big.Int `json:"maxFeePerGas,omitempty"` - MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas,omitempty"` - Origin thor.Address `json:"origin"` - Delegator *thor.Address `json:"delegator"` - Nonce math.HexOrDecimal64 `json:"nonce"` - DependsOn *thor.Bytes32 `json:"dependsOn"` - Size uint32 `json:"size"` - Meta *TxMeta `json:"meta"` -} - type RawTx struct { Raw string `json:"raw"` } @@ -86,44 +66,6 @@ type RawTransaction struct { Meta *TxMeta `json:"meta"` } -// convertTransaction convert a raw transaction into a json format transaction -func convertTransaction(tx *tx.Transaction, header *block.Header) *Transaction { - //tx origin - origin, _ := tx.Origin() - delegator, _ := tx.Delegator() - - cls := make(Clauses, len(tx.Clauses())) - for i, c := range tx.Clauses() { - cls[i] = convertClause(c) - } - br := tx.BlockRef() - t := &Transaction{ - ChainTag: tx.ChainTag(), - ID: tx.ID(), - Origin: origin, - BlockRef: hexutil.Encode(br[:]), - Expiration: tx.Expiration(), - Nonce: math.HexOrDecimal64(tx.Nonce()), - Size: uint32(tx.Size()), - GasPriceCoef: tx.GasPriceCoef(), - Gas: tx.Gas(), - DependsOn: tx.DependsOn(), - Clauses: cls, - Delegator: delegator, - MaxFeePerGas: tx.MaxFeePerGas(), - MaxPriorityFeePerGas: tx.MaxPriorityFeePerGas(), - } - - if header != nil { - t.Meta = &TxMeta{ - BlockID: header.ID(), - BlockNumber: header.Number(), - BlockTimestamp: header.Timestamp(), - } - } - return t -} - type TxMeta struct { BlockID thor.Bytes32 `json:"blockID"` BlockNumber uint32 `json:"blockNumber"`