Skip to content

test(protocol): localstatequery using cardano blueprint tests #1001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions .github/workflows/go-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "cardano-blueprint"]
path = cardano-blueprint
url = [email protected]:cardano-scaling/cardano-blueprint
1 change: 1 addition & 0 deletions cardano-blueprint
Submodule cardano-blueprint added at e70779
4 changes: 3 additions & 1 deletion cmd/gouroboros/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ func testQuery(f *globalFlags) {
os.Exit(1)
}
fmt.Printf(
"system-start: year = %d, day = %d, picoseconds = %d\n",
// REVIEW: %d should work for big/Int, but warns and produces output
// like {%!d(bool=false) [2025]}
"system-start: year = %v, day = %d, picoseconds = %v\n",
systemStart.Year,
systemStart.Day,
systemStart.Picoseconds,
Expand Down
5 changes: 3 additions & 2 deletions protocol/localstatequery/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package localstatequery_test
import (
"encoding/json"
"fmt"
"math/big"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -290,9 +291,9 @@ func TestGetUTxOByAddress(t *testing.T) {
func TestGenesisConfigJSON(t *testing.T) {
genesisConfig := localstatequery.GenesisConfigResult{
Start: localstatequery.SystemStartResult{
Year: 2024,
Year: *big.NewInt(2024),
Day: 35,
Picoseconds: 1234567890123456,
Picoseconds: *big.NewInt(1234567890123456),
},
NetworkMagic: 764824073,
NetworkId: 1,
Expand Down
68 changes: 68 additions & 0 deletions protocol/localstatequery/messages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ package localstatequery

import (
"encoding/hex"
"fmt"
"math/big"
"os"
"reflect"
"testing"

Expand All @@ -28,6 +31,7 @@ type testDefinition struct {
CborHex string
Message protocol.Message
MessageType uint
Result interface{}
}

var tests = []testDefinition{
Expand Down Expand Up @@ -92,6 +96,26 @@ var tests = []testDefinition{
Message: NewMsgReAcquireVolatileTip(),
MessageType: MessageTypeReacquireVolatileTip,
},
{
CborHex: string(readFile("../../cardano-blueprint/src/api/examples/getSystemStart/query.cbor")),
Message: NewMsgQuery(&SystemStartQuery{simpleQueryBase{Type: QueryTypeSystemStart}}),
MessageType: MessageTypeQuery,
},
{
CborHex: string(readFile("../../cardano-blueprint/src/api/examples/getSystemStart/result.cbor")),
Message: NewMsgResult(unsafeCbor(
SystemStartResult{
Year: unsafeBigInt([]byte("703941703872597091335551638723343370661404331303175992839224705786473148")),
Day: -4205646576720553090,
Picoseconds: unsafeBigInt([]byte("-554918151390414980540174869115975093799476848534297657333456993160799627")),
})),
MessageType: MessageTypeResult,
Result: SystemStartResult{
Year: unsafeBigInt([]byte("703941703872597091335551638723343370661404331303175992839224705786473148")),
Day: -4205646576720553090,
Picoseconds: unsafeBigInt([]byte("-554918151390414980540174869115975093799476848534297657333456993160799627")),
},
},
}

func TestDecode(t *testing.T) {
Expand All @@ -104,6 +128,23 @@ func TestDecode(t *testing.T) {
if err != nil {
t.Fatalf("failed to decode CBOR: %s", err)
}
// cast msg to MsgResult and further try to decode cbor
if m, ok := msg.(*MsgResult); ok && test.Result != nil {
var decoded = reflect.New(reflect.TypeOf(test.Result))
_, err := cbor.Decode(m.Result, decoded.Interface())
if err != nil {
t.Fatalf("failed to decode result: %s", err)
}
var actual = reflect.Indirect(decoded).Interface()
if !reflect.DeepEqual(actual, test.Result) {
t.Fatalf(
"MsgResult content did not decode to expected Result object\n got: %#v\n wanted: %#v",
actual,
test.Result,
)
}
}

// Set the raw CBOR so the comparison should succeed
test.Message.SetCbor(cborData)
if m, ok := msg.(*MsgQuery); ok {
Expand Down Expand Up @@ -135,3 +176,30 @@ func TestEncode(t *testing.T) {
}
}
}

// Helper function to encode to cbor or panic
func unsafeCbor(data interface{}) []byte {
cborData, err := cbor.Encode(data)
if err != nil {
panic(fmt.Sprintf("error encoding to CBOR: %s", err))
}
return cborData
}

func unsafeBigInt(text []byte) big.Int {
var i big.Int
err := i.UnmarshalText(text)
if err != nil {
panic(fmt.Sprintf("error unmarshalling text to big.Int: %s", err))
}
return i
}

// Helper function to allow inline reading of a file without capturing the error
func readFile(path string) []byte {
data, err := os.ReadFile(path)
if err != nil {
panic(fmt.Sprintf("error reading file: %s", err))
}
return data
}
37 changes: 35 additions & 2 deletions protocol/localstatequery/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
package localstatequery

import (
"encoding/json"
"fmt"
"math/big"

"github.com/blinklabs-io/gouroboros/cbor"
"github.com/blinklabs-io/gouroboros/ledger"
Expand Down Expand Up @@ -416,9 +418,40 @@ type SystemStartQuery struct {
type SystemStartResult struct {
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
_ struct{} `cbor:",toarray"`
Year int
Year big.Int
Day int
Picoseconds uint64
Picoseconds big.Int
}

func (s SystemStartResult) String() string {
return fmt.Sprintf("SystemStart %s %d %s", s.Year.String(), s.Day, s.Picoseconds.String())
}

func (s SystemStartResult) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Year string `json:"year"`
Day int `json:"day"`
Picoseconds string `json:"picoseconds"`
}{
Year: s.Year.String(),
Day: s.Day,
Picoseconds: s.Picoseconds.String(),
})
}

func (s *SystemStartResult) UnmarshalJSON(data []byte) error {
var tmp struct {
Year string `json:"year"`
Day int `json:"day"`
Picoseconds string `json:"picoseconds"`
}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
s.Year.SetString(tmp.Year, 10)
s.Day = tmp.Day
s.Picoseconds.SetString(tmp.Picoseconds, 10)
return nil
}

type ChainBlockNoQuery struct {
Expand Down
Loading