-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
1,927 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package lightclient | ||
|
||
import ( | ||
"encoding/hex" | ||
"encoding/json" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/attestantio/go-eth2-client/spec/phase0" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// BeaconBlockHeader represents a beacon block header. | ||
type BeaconBlockHeader struct { | ||
Slot phase0.Slot `json:"slot"` | ||
ProposerIndex phase0.ValidatorIndex `json:"proposer_index"` | ||
ParentRoot phase0.Root `json:"parent_root"` | ||
StateRoot phase0.Root `json:"state_root"` | ||
BodyRoot phase0.Root `json:"body_root"` | ||
} | ||
|
||
type beaconBlockHeaderJSON struct { | ||
Slot string `json:"slot"` | ||
ProposerIndex string `json:"proposer_index"` | ||
ParentRoot string `json:"parent_root"` | ||
StateRoot string `json:"state_root"` | ||
BodyRoot string `json:"body_root"` | ||
} | ||
|
||
func (h *BeaconBlockHeader) ToJSON() beaconBlockHeaderJSON { | ||
return beaconBlockHeaderJSON{ | ||
Slot: fmt.Sprintf("%d", h.Slot), | ||
ProposerIndex: fmt.Sprintf("%d", h.ProposerIndex), | ||
ParentRoot: h.ParentRoot.String(), | ||
StateRoot: h.StateRoot.String(), | ||
BodyRoot: h.BodyRoot.String(), | ||
} | ||
} | ||
|
||
func (h *BeaconBlockHeader) FromJSON(data beaconBlockHeaderJSON) error { | ||
slot, err := strconv.ParseUint(data.Slot, 10, 64) | ||
if err != nil { | ||
return errors.Wrap(err, "invalid slot") | ||
} | ||
h.Slot = phase0.Slot(slot) | ||
|
||
proposerIndex, err := strconv.ParseUint(data.ProposerIndex, 10, 64) | ||
if err != nil { | ||
return errors.Wrap(err, "invalid proposer index") | ||
} | ||
h.ProposerIndex = phase0.ValidatorIndex(proposerIndex) | ||
|
||
parentRoot, err := hex.DecodeString(strings.TrimPrefix(data.ParentRoot, "0x")) | ||
if err != nil { | ||
return errors.Wrap(err, "invalid parent root") | ||
} | ||
h.ParentRoot = phase0.Root(parentRoot) | ||
|
||
stateRoot, err := hex.DecodeString(strings.TrimPrefix(data.StateRoot, "0x")) | ||
if err != nil { | ||
return errors.Wrap(err, "invalid state root") | ||
} | ||
h.StateRoot = phase0.Root(stateRoot) | ||
|
||
bodyRoot, err := hex.DecodeString(strings.TrimPrefix(data.BodyRoot, "0x")) | ||
if err != nil { | ||
return errors.Wrap(err, "invalid body root") | ||
} | ||
h.BodyRoot = phase0.Root(bodyRoot) | ||
|
||
return nil | ||
} | ||
|
||
func (h BeaconBlockHeader) MarshalJSON() ([]byte, error) { | ||
return json.Marshal(h.ToJSON()) | ||
} | ||
|
||
func (h *BeaconBlockHeader) UnmarshalJSON(data []byte) error { | ||
var jsonData beaconBlockHeaderJSON | ||
if err := json.Unmarshal(data, &jsonData); err != nil { | ||
return err | ||
} | ||
return h.FromJSON(jsonData) | ||
} |
84 changes: 84 additions & 0 deletions
84
pkg/beacon/api/types/lightclient/beacon_block_header_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package lightclient_test | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/attestantio/go-eth2-client/spec/phase0" | ||
"github.com/ethpandaops/beacon/pkg/beacon/api/types/lightclient" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestBeaconBlockHeaderMarshalUnmarshal(t *testing.T) { | ||
testCases := []struct { | ||
name string | ||
header lightclient.BeaconBlockHeader | ||
}{ | ||
{ | ||
name: "Basic BeaconBlockHeader", | ||
header: lightclient.BeaconBlockHeader{ | ||
Slot: 1234, | ||
ProposerIndex: 5678, | ||
ParentRoot: phase0.Root{0x01, 0x02, 0x03}, | ||
StateRoot: phase0.Root{0x04, 0x05, 0x06}, | ||
BodyRoot: phase0.Root{0x07, 0x08, 0x09}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
marshaled, err := json.Marshal(tc.header) | ||
if err != nil { | ||
t.Fatalf("Failed to marshal LightClientHeader: %v", err) | ||
} | ||
|
||
var unmarshaled lightclient.LightClientHeader | ||
err = json.Unmarshal(marshaled, &unmarshaled) | ||
if err != nil { | ||
t.Fatalf("Failed to unmarshal LightClientHeader: %v", err) | ||
} | ||
|
||
if !reflect.DeepEqual(tc.header, unmarshaled) { | ||
t.Errorf("Unmarshaled LightClientHeader does not match original. Got %+v, want %+v", unmarshaled, tc.header) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestBeaconBlockHeaderUnmarshalJSON(t *testing.T) { | ||
expectedSlot := "1" | ||
expectedProposerIndex := "1" | ||
expectedParentRoot := "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" | ||
expectedStateRoot := "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" | ||
expectedBodyRoot := "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" | ||
|
||
jsonStr := `{ | ||
"slot": "` + expectedSlot + `", | ||
"proposer_index": "` + expectedProposerIndex + `", | ||
"parent_root": "` + expectedParentRoot + `", | ||
"state_root": "` + expectedStateRoot + `", | ||
"body_root": "` + expectedBodyRoot + `" | ||
}` | ||
|
||
var header lightclient.BeaconBlockHeader | ||
err := json.Unmarshal([]byte(jsonStr), &header) | ||
require.NoError(t, err) | ||
|
||
assert.Equal(t, expectedSlot, fmt.Sprintf("%d", header.Slot)) | ||
assert.Equal(t, expectedProposerIndex, fmt.Sprintf("%d", header.ProposerIndex)) | ||
assert.Equal(t, expectedParentRoot, header.ParentRoot.String()) | ||
assert.Equal(t, expectedStateRoot, header.StateRoot.String()) | ||
assert.Equal(t, expectedBodyRoot, header.BodyRoot.String()) | ||
|
||
// Test marshalling back to JSON | ||
marshaled, err := json.Marshal(header) | ||
require.NoError(t, err) | ||
|
||
var unmarshaled lightclient.BeaconBlockHeader | ||
err = json.Unmarshal(marshaled, &unmarshaled) | ||
require.NoError(t, err) | ||
} |
Oops, something went wrong.