diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..dac4b4ba --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cardano-blueprint"] + path = cardano-blueprint + url = git@github.com:cardano-scaling/cardano-blueprint diff --git a/cardano-blueprint b/cardano-blueprint new file mode 160000 index 00000000..e707795c --- /dev/null +++ b/cardano-blueprint @@ -0,0 +1 @@ +Subproject commit e707795ca8c82bdbe1a6c4aca6698b30503dd3b9 diff --git a/cmd/gouroboros/query.go b/cmd/gouroboros/query.go index 7c980b10..c562ddb6 100644 --- a/cmd/gouroboros/query.go +++ b/cmd/gouroboros/query.go @@ -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, diff --git a/protocol/localstatequery/client_test.go b/protocol/localstatequery/client_test.go index 625a4cb5..563b16e8 100644 --- a/protocol/localstatequery/client_test.go +++ b/protocol/localstatequery/client_test.go @@ -17,6 +17,7 @@ package localstatequery_test import ( "encoding/json" "fmt" + "math/big" "reflect" "testing" "time" @@ -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, diff --git a/protocol/localstatequery/messages_test.go b/protocol/localstatequery/messages_test.go index 8538557b..5570fef3 100644 --- a/protocol/localstatequery/messages_test.go +++ b/protocol/localstatequery/messages_test.go @@ -16,6 +16,9 @@ package localstatequery import ( "encoding/hex" + "fmt" + "math/big" + "os" "reflect" "testing" @@ -28,6 +31,7 @@ type testDefinition struct { CborHex string Message protocol.Message MessageType uint + Result interface{} } var tests = []testDefinition{ @@ -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) { @@ -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 { @@ -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 +} diff --git a/protocol/localstatequery/queries.go b/protocol/localstatequery/queries.go index 5f017e02..f3ceaa98 100644 --- a/protocol/localstatequery/queries.go +++ b/protocol/localstatequery/queries.go @@ -15,7 +15,9 @@ package localstatequery import ( + "encoding/json" "fmt" + "math/big" "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/gouroboros/ledger" @@ -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 + Day int + Picoseconds string + }{ + Year: s.Year.String(), + Day: s.Day, + Picoseconds: s.Picoseconds.String(), + }) +} + +func (s *SystemStartResult) UnmarshalJSON(data []byte) error { + var tmp struct { + Year string + Day int + Picoseconds string + } + 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 {