Skip to content

Commit

Permalink
BCF-2117 More thorough block JSON testing (#8637)
Browse files Browse the repository at this point in the history
  • Loading branch information
krehermann authored Mar 7, 2023
1 parent 9bb1fd2 commit 3b367c0
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 12 deletions.
88 changes: 88 additions & 0 deletions core/chains/evm/types/block_json_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package types

import (
"encoding/binary"
"encoding/json"
"math/big"
"testing"
"time"

"github.com/ethereum/go-ethereum/common"

"github.com/smartcontractkit/chainlink/core/assets"
)

func makeTestBlock(nTx int) *Block {
txns := make([]Transaction, nTx)

generateHash := func(x int64) common.Hash {
out := make([]byte, 0, 32)

b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(x))

for i := 0; i < 4; i++ {
out = append(out, b...)
}
return common.BytesToHash(out)
}
for i := 0; i < nTx; i++ {
wei := assets.NewWei(big.NewInt(int64(i)))
txns[i] = Transaction{
GasPrice: wei,
GasLimit: uint32(i),
MaxFeePerGas: wei,
MaxPriorityFeePerGas: wei,
Type: 0,
Hash: generateHash(int64(i)),
}
}
return &Block{
Number: int64(nTx),
Hash: generateHash(int64(1024 * 1024)),
ParentHash: generateHash(int64(512 * 1024)),
BaseFeePerGas: assets.NewWei(big.NewInt(3)),
Timestamp: time.Now(),
Transactions: txns,
}
}

var (
smallBlock = makeTestBlock(2)
mediumBlock = makeTestBlock(64)
largeBlock = makeTestBlock(512)
xlBlock = makeTestBlock(4 * 1024)
)

func unmarshal_block(b *testing.B, block *Block) {
jsonBytes, err := json.Marshal(&block)
if err != nil {
b.Fatalf("failed to create test json %+v", err)
}
b.ResetTimer()

var temp Block
for i := 0; i < b.N; i++ {
err := json.Unmarshal(jsonBytes, &temp)
if err != nil {
b.Fatalf("err %+v", err)
}
}
}

func BenchmarkBlock_Small_JSONUnmarshal(b *testing.B) {
unmarshal_block(b, smallBlock)

}

func BenchmarkBlock_Medium_JSONUnmarshal(b *testing.B) {
unmarshal_block(b, mediumBlock)
}

func BenchmarkBlock_Large_JSONUnmarshal(b *testing.B) {
unmarshal_block(b, largeBlock)
}

func BenchmarkBlock_XL_JSONUnmarshal(b *testing.B) {
unmarshal_block(b, xlBlock)
}
43 changes: 31 additions & 12 deletions core/chains/evm/types/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,12 @@ type Block struct {
}

type blockInternal struct {
Number string
Hash common.Hash
ParentHash common.Hash
BaseFeePerGas *hexutil.Big
Timestamp hexutil.Uint64
Transactions []Transaction
Number string `json:"number"`
Hash common.Hash `json:"hash"`
ParentHash common.Hash `json:"parentHash"`
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas"`
Timestamp hexutil.Uint64 `json:"timestamp"`
Transactions []Transaction `json:"transactions"`
}

// MarshalJSON implements json marshalling for Block
Expand Down Expand Up @@ -339,6 +339,11 @@ func (txt *TxType) UnmarshalJSON(data []byte) error {
return nil
}

func (txt *TxType) MarshalText() ([]byte, error) {
hx := (hexutil.Uint64)(*txt)
return hx.MarshalText()
}

type transactionInternal struct {
GasPrice *hexutil.Big `json:"gasPrice"`
Gas *hexutil.Uint64 `json:"gas"`
Expand All @@ -353,12 +358,12 @@ type transactionInternal struct {
// gas used, which can occur on other chains.
// This type is only used for the block history estimator, and can be expensive to unmarshal. Don't add unnecessary fields here.
type Transaction struct {
GasPrice *assets.Wei
GasLimit uint32
MaxFeePerGas *assets.Wei
MaxPriorityFeePerGas *assets.Wei
Type TxType
Hash common.Hash
GasPrice *assets.Wei `json:"gasPrice"`
GasLimit uint32 `json:"gasLimit"`
MaxFeePerGas *assets.Wei `json:"maxFeePerGas"`
MaxPriorityFeePerGas *assets.Wei `json:"maxPriorityFeePerGas"`
Type TxType `json:"type"`
Hash common.Hash `json:"hash"`
}

const LegacyTxType = TxType(0x0)
Expand Down Expand Up @@ -387,6 +392,20 @@ func (t *Transaction) UnmarshalJSON(data []byte) error {
return nil
}

func (t *Transaction) MarshalJSON() ([]byte, error) {

gas := (hexutil.Uint64)(uint64(t.GasLimit))
ti := &transactionInternal{
GasPrice: (*hexutil.Big)(t.GasPrice),
Gas: &gas,
MaxFeePerGas: (*hexutil.Big)(t.MaxFeePerGas),
MaxPriorityFeePerGas: (*hexutil.Big)(t.MaxPriorityFeePerGas),
Type: &t.Type,
Hash: t.Hash,
}
return json.Marshal(ti)
}

// WeiPerEth is amount of Wei currency units in one Eth.
var WeiPerEth = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)

Expand Down
148 changes: 148 additions & 0 deletions core/chains/evm/types/models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -723,3 +724,150 @@ func TestBlock_UnmarshalJSON(t *testing.T) {
assert.True(t, errors.Is(err, evmtypes.ErrMissingBlock))
})
}

func TestTransaction_UnmarshalJSON(t *testing.T) {
t.Parallel()
type args struct {
data []byte
}
tests := []struct {
name string
args args
wantErr bool
want *evmtypes.Transaction
}{
{
name: "sample geth txn",
args: args{
[]byte(
`{
"blockHash": "0x45eb0a650b6b0b9fd1ee676b870e43fa7614f1034f7404070327a332faed05c0",
"blockNumber": "0xe5a952",
"from": "0x76e40d0a69fd81826b5eb7d18145626d46eafdef",
"gas": "0xdbba0",
"gasPrice": "0x978a846d2",
"maxFeePerGas": "0xd0892241d",
"maxPriorityFeePerGas": "0x3b9aca01",
"hash": "0x754f49f0a2ca7680806d261dd36ee95ac88a81da59fef0b5d8d691478f075d46",
"input": "0x1cff79cd000000000000000000000000343933efdf64d2d6eeaf2dcd5fbd701541d64f67000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e44a7d794a000000000000000000000000000000000000000000000005bc94810a20626a9a0000000000000000000000000000000000000000000000000e52b79acdb06152000000000000000000000000000000000000798f836298dfb377b3deeb7ade400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000062bdc2400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000798e37fb7bc47a14e3b89fa086d600000000000000000000000000000000000000000000000000000000",
"nonce": "0xbf65",
"to": "0x4cb18386e5d1f34dc6eea834bf3534a970a3f8e7",
"transactionIndex": "0x0",
"value": "0xa907",
"type": "0x2",
"accessList": [],
"chainId": "0x1",
"v": "0x0",
"r": "0xcbdf4705610d7b20326dcd153491f37f133c34026f3e0abf72f9db03ac98de0e",
"s": "0xa2b2d625d34315e8d6d0543e0f9393d2a14dddaf3678d7f0ed432df9cb8e5c3"
}`,
),
},
want: &evmtypes.Transaction{
GasPrice: assets.NewWei(utils.HexToBig("978a846d2")),
GasLimit: mustHextoUint32(t, "0xdbba0"),
MaxFeePerGas: assets.NewWei(utils.HexToBig("d0892241d")),
MaxPriorityFeePerGas: assets.NewWei(utils.HexToBig("3b9aca01")),
Type: 0x2,
Hash: common.HexToHash("0x754f49f0a2ca7680806d261dd36ee95ac88a81da59fef0b5d8d691478f075d46"),
},
},
{
name: "sample parity txn",
args: args{[]byte(
` {
"blockHash": "0x0ec62c2a397e114d84ce932387d841787d7ec5757ceba3708386da87934b7c82",
"blockNumber": "0x1ef81ff",
"chainId": null,
"condition": null,
"creates": null,
"from": "0xe6d63ed2c574b150a205d1d9cc7aaff1b7e4b59d",
"gas": "0x2dc6c0",
"gasPrice": "0x4f7915f5",
"hash": "0xbe6122d6aaf84fb85f4df136d4662c6dc344248e987255c0daa1193b3f17d5a9",
"input": "0xfdacd5760000000000000000000000000000000000000000000000000000000000000001",
"nonce": "0x7",
"publicKey": "0xb2a40fd8ec8703916fde9a0d3bb3c2391d7a2a1a6c1cd6492a7842d9daed24d5064847aaa242e635440f6dd06107044e1bd9387da6c32da3eaee56b928c6bdbf",
"r": "0x4b3f442f3a014468b40d2fadea1b152b36582420d28fb69695658be40ffbdffa",
"raw": "0xf88807844f7915f5832dc6c0949c97d0e47d81e0ffd0e41450427973e30ff1657b80a4fdacd57600000000000000000000000000000000000000000000000000000000000000011ba04b3f442f3a014468b40d2fadea1b152b36582420d28fb69695658be40ffbdffaa065f626f3a91ca662e56c42ea4376ee8f3db65a4ad613b9bdd2776c292869fee7",
"s": "0x65f626f3a91ca662e56c42ea4376ee8f3db65a4ad613b9bdd2776c292869fee7",
"standardV": "0x0",
"to": "0x9c97d0e47d81e0ffd0e41450427973e30ff1657b",
"transactionIndex": "0x1",
"v": "0x1b",
"value": "0x0"
}`,
)},
want: &evmtypes.Transaction{
GasPrice: assets.NewWei(utils.HexToBig("4f7915f5")),
GasLimit: mustHextoUint32(t, "0x2dc6c0"),
MaxFeePerGas: nil,
MaxPriorityFeePerGas: nil,
Type: 0,
Hash: common.HexToHash("0xbe6122d6aaf84fb85f4df136d4662c6dc344248e987255c0daa1193b3f17d5a9"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := &evmtypes.Transaction{}
err := got.UnmarshalJSON(tt.args.data)
require.NoError(t, err)
require.Equal(t, tt.want, got)

})
}
}

func TestTransaction_JSONRoundtrip(t *testing.T) {
t.Parallel()
want := &evmtypes.Transaction{
GasPrice: assets.NewWei(utils.HexToBig("978a846d2")),
GasLimit: mustHextoUint32(t, "0xdbba0"),
MaxFeePerGas: assets.NewWei(utils.HexToBig("d0892241d")),
MaxPriorityFeePerGas: assets.NewWei(utils.HexToBig("3b9aca01")),
Type: evmtypes.TxType(2),
Hash: common.HexToHash("0x754f49f0a2ca7680806d261dd36ee95ac88a81da59fef0b5d8d691478f075d46"),
}

d, err := json.Marshal(want)
require.NoError(t, err)
got := new(evmtypes.Transaction)
err = json.Unmarshal(d, got)
require.NoError(t, err)
assert.Equal(t, want, got)
}

func TestTxType_JSONRoundtrip(t *testing.T) {

t.Run("non zero", func(t *testing.T) {
t.Parallel()
want := evmtypes.TxType(2)
d, err := json.Marshal(&want)
require.NoError(t, err)

got := new(evmtypes.TxType)
err = json.Unmarshal(d, got)
require.NoError(t, err)
assert.Equal(t, want, *got)
})

t.Run("zero", func(t *testing.T) {
t.Parallel()
want := evmtypes.TxType(0)
d, err := json.Marshal(&want)
require.NoError(t, err)

got := new(evmtypes.TxType)
err = json.Unmarshal(d, got)
require.NoError(t, err)
assert.Equal(t, want, *got)
})
}

func mustHextoUint32(t *testing.T, hx string) uint32 {
temp := new(hexutil.Uint64)
err := temp.UnmarshalText([]byte(hx))
require.NoError(t, err)
return uint32(*temp)
}

0 comments on commit 3b367c0

Please sign in to comment.