Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Add custom marshalling and unmarshalling for block Header #642

Merged
merged 20 commits into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions helper/hex/hex.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ func EncodeUint64(i uint64) string {
return string(strconv.AppendUint(enc, i, 16))
}

// DecodeUint64 decodes a hex string with 0x prefix to uint64
func DecodeUint64(hexStr string) (uint64, error) {
// remove 0x suffix if found in the input string
cleaned := strings.TrimPrefix(hexStr, "0x")

return strconv.ParseUint(cleaned, 16, 64)
}

const BadNibble = ^uint64(0)

// DecodeNibble decodes a byte into a uint64
Expand Down
25 changes: 25 additions & 0 deletions helper/hex/hex_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package hex

import (
"github.com/stretchr/testify/assert"
"testing"
)

const (
minUint64 uint64 = 0
maxUint64 uint64 = 18446744073709551615
)

func TestEncodingUint64(t *testing.T) {
// random uint64 array, min and max included
uint64Array := [10]uint64{minUint64, 30073, 67312, 71762, 11, 80604, 45403, 1, 298, maxUint64}

for _, value := range uint64Array {
encodedValue := EncodeUint64(value)

decodedValue, err := DecodeUint64(encodedValue)
assert.NoError(t, err)

assert.Equal(t, value, decodedValue)
}
}
4 changes: 4 additions & 0 deletions types/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,7 @@ func EncodeBigInt(b *big.Int) *string {

return &res
}

func RemoveHexPrefixFromByteArray(input []byte) []byte {
return input[2:]
}
108 changes: 108 additions & 0 deletions types/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package types
import (
"database/sql/driver"
"encoding/binary"
goHex "encoding/hex"
"encoding/json"
"errors"
"fmt"
"sync/atomic"
Expand Down Expand Up @@ -30,6 +32,103 @@ type Header struct {
Hash Hash `json:"hash"`
}

// HeaderJson represents a block header used for json calls
type headerJSON struct {
ParentHash Hash `json:"parentHash"`
Sha3Uncles Hash `json:"sha3Uncles"`
Miner Address `json:"miner"`
StateRoot Hash `json:"stateRoot"`
TxRoot Hash `json:"transactionsRoot"`
ReceiptsRoot Hash `json:"receiptsRoot"`
LogsBloom Bloom `json:"logsBloom"`
Difficulty string `json:"difficulty"`
Number string `json:"number"`
GasLimit string `json:"gasLimit"`
GasUsed string `json:"gasUsed"`
Timestamp string `json:"timestamp"`
ExtraData string `json:"extraData"`
MixHash Hash `json:"mixHash"`
Nonce Nonce `json:"nonce"`
Hash Hash `json:"hash"`
}

func (h *Header) MarshalJSON() ([]byte, error) {
var header headerJSON

header.ParentHash = h.ParentHash
header.Sha3Uncles = h.Sha3Uncles
header.Miner = h.Miner
header.StateRoot = h.StateRoot
header.TxRoot = h.TxRoot
header.ReceiptsRoot = h.ReceiptsRoot
header.LogsBloom = h.LogsBloom

header.MixHash = h.MixHash
header.Nonce = h.Nonce
header.Hash = h.Hash

header.Difficulty = hex.EncodeUint64(h.Difficulty)
header.Number = hex.EncodeUint64(h.Number)
header.GasLimit = hex.EncodeUint64(h.GasLimit)
header.GasUsed = hex.EncodeUint64(h.GasUsed)
header.Timestamp = hex.EncodeUint64(h.Timestamp)
header.ExtraData = hex.EncodeToHex(h.ExtraData)

return json.Marshal(&header)
}

func (h *Header) UnmarshalJSON(input []byte) error {
var header headerJSON
if err := json.Unmarshal(input, &header); err != nil {
return err
}

h.ParentHash = header.ParentHash
h.Sha3Uncles = header.Sha3Uncles
h.Miner = header.Miner
h.StateRoot = header.StateRoot
h.TxRoot = header.TxRoot
h.ReceiptsRoot = header.ReceiptsRoot
h.LogsBloom = header.LogsBloom
h.MixHash = header.MixHash
h.Nonce = header.Nonce
h.Hash = header.Hash

var err error

h.Difficulty, err = hex.DecodeUint64(header.Difficulty)
if err != nil {
return err
}

h.Number, err = hex.DecodeUint64(header.Number)
if err != nil {
return err
}

h.GasLimit, err = hex.DecodeUint64(header.GasLimit)
if err != nil {
return err
}

h.GasUsed, err = hex.DecodeUint64(header.GasUsed)
if err != nil {
return err
}

h.Timestamp, err = hex.DecodeUint64(header.Timestamp)
if err != nil {
return err
}

h.ExtraData, err = hex.DecodeHex(header.ExtraData)
if err != nil {
return err
}

return nil
}

func (h *Header) Equal(hh *Header) bool {
return h.Hash == hh.Hash
}
Expand Down Expand Up @@ -77,6 +176,15 @@ func (n Nonce) MarshalText() ([]byte, error) {
return []byte(n.String()), nil
}

func (n *Nonce) UnmarshalText(input []byte) error {
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
input = RemoveHexPrefixFromByteArray(input)
if _, err := goHex.Decode(n[:], input); err != nil {
return err
}

return nil
}

func (h *Header) Copy() *Header {
hh := new(Header)
*hh = *h
Expand Down
96 changes: 96 additions & 0 deletions types/header_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package types

import (
"encoding/json"
"github.com/stretchr/testify/assert"
"reflect"
"testing"
)

func TestHeaderType_Encode(t *testing.T) {
header := Header{
ParentHash: Hash{0x1},
Sha3Uncles: Hash{0x2},
Miner: Address{0x1},
StateRoot: Hash{0x4},
TxRoot: Hash{0x5},
ReceiptsRoot: Hash{0x6},
LogsBloom: Bloom{0x1},
Difficulty: 10,
Number: 11,
GasLimit: 12,
GasUsed: 13,
Timestamp: 14,
ExtraData: []byte{97, 98, 99, 100, 101, 102},
MixHash: Hash{0x7},
Nonce: Nonce{10},
Hash: Hash{0x8},
}

headerJSON, err := json.Marshal(&header)
if err != nil {
t.Fatalf("Unable marshall header, %v", err)
}

unmarshallHeader := Header{}
assert.NoError(t, json.Unmarshal(headerJSON, &unmarshallHeader))

if !reflect.DeepEqual(unmarshallHeader, header) {
t.Fatal("Resulting data and expected values are not equal")
}
}
Kourin1996 marked this conversation as resolved.
Show resolved Hide resolved

func TestUnmarshallFromJSON(t *testing.T) {
testCase := struct {
input string
output Header
}{
input: `{
"parentHash": "0x0100000000000000000000000000000000000000000000000000000000000000",
"sha3Uncles" : "0x0200000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0100000000000000000000000000000000000000",
"stateRoot" : "0x0400000000000000000000000000000000000000000000000000000000000000",
"transactionsRoot" : "0x0500000000000000000000000000000000000000000000000000000000000000",
"receiptsRoot" : "0x0600000000000000000000000000000000000000000000000000000000000000",
"logsBloom" : "0x01",
"difficulty" : "0xa",
"number" : "0xb",
"gasLimit" : "0xc",
"gasUsed" : "0xd",
"timestamp" : "0xe",
"extraData":"0x616263646566",
"mixHash" : "0x0700000000000000000000000000000000000000000000000000000000000000",
"nonce" : "0x0a00000000000000",
"hash" : "0x0800000000000000000000000000000000000000000000000000000000000000"
}`,
output: Header{
ParentHash: Hash{0x1},
Sha3Uncles: Hash{0x2},
Miner: Address{0x1},
StateRoot: Hash{0x4},
TxRoot: Hash{0x5},
ReceiptsRoot: Hash{0x6},
LogsBloom: Bloom{0x1},
Difficulty: 10,
Number: 11,
GasLimit: 12,
GasUsed: 13,
Timestamp: 14,
ExtraData: []byte{97, 98, 99, 100, 101, 102},
MixHash: Hash{0x7},
Nonce: Nonce{10},
Hash: Hash{0x8},
},
}

unmarshallHeader := Header{}

err := json.Unmarshal([]byte(testCase.input), &unmarshallHeader)
if err != nil {
t.Fatalf("Unable to decode header, %v", err)
}

if !reflect.DeepEqual(unmarshallHeader, testCase.output) {
t.Fatal("Resulting data and expected values are not equal")
}
}
2 changes: 1 addition & 1 deletion types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const BloomByteLength = 256
type Bloom [BloomByteLength]byte

func (b *Bloom) UnmarshalText(input []byte) error {
input = input[2:]
input = RemoveHexPrefixFromByteArray(input)
if _, err := goHex.Decode(b[:], input); err != nil {
return err
}
Expand Down