Skip to content

Commit

Permalink
feat: support for loading cardano-node and genesis configs
Browse files Browse the repository at this point in the history
This commit also includes the upstream cardano-node and genesis config
files for the preview network
  • Loading branch information
agaffney committed Sep 30, 2024
1 parent e445db2 commit 177fd97
Show file tree
Hide file tree
Showing 14 changed files with 1,030 additions and 10 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ RUN make build

FROM debian:bookworm-slim AS node
COPY --from=build /code/node /bin/
COPY ./configs/cardano /opt/cardano/configs
ENV CARDANO_CONFIG=/opt/cardano/configs/preview/config.json
ENTRYPOINT ["node"]
10 changes: 10 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"io"
"log/slog"

"github.com/blinklabs-io/node/config/cardano"
"github.com/blinklabs-io/node/topology"

ouroboros "github.com/blinklabs-io/gouroboros"
Expand All @@ -27,6 +28,7 @@ import (
)

type Config struct {
cardanoNodeConfig *cardano.CardanoNodeConfig
dataDir string
intersectPoints []ocommon.Point
intersectTip bool
Expand Down Expand Up @@ -98,6 +100,14 @@ func NewConfig(opts ...ConfigOptionFunc) Config {
return c
}

// WithCardanoNodeConfig specifies the CardanoNodeConfig object to use. This is mostly used for loading genesis config files
// referenced by the node config
func WithCardanoNodeConfig(cardanoNodeConfig *cardano.CardanoNodeConfig) ConfigOptionFunc {
return func(c *Config) {
c.cardanoNodeConfig = cardanoNodeConfig
}
}

// WithDataDir specifies the persistent data directory to use. The default is to store everything in memory
func WithDataDir(dataDir string) ConfigOptionFunc {
return func(c *Config) {
Expand Down
107 changes: 107 additions & 0 deletions config/cardano/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2024 Blink Labs Software
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cardano

import (
"io"
"os"
"path"

"github.com/blinklabs-io/gouroboros/ledger/alonzo"
"github.com/blinklabs-io/gouroboros/ledger/byron"
"github.com/blinklabs-io/gouroboros/ledger/conway"
"github.com/blinklabs-io/gouroboros/ledger/shelley"
"gopkg.in/yaml.v3"
)

// CardanoNodeConfig represents the config.json/yaml file used by cardano-node
type CardanoNodeConfig struct {
path string
AlonzoGenesisFile string `yaml:"AlonzoGenesisFile"`
AlonzoGenesisHash string `yaml:"AlonzoGenesisHash"`
ByronGenesisFile string `yaml:"ByronGenesisFile"`
ByronGenesisHash string `yaml:"ByronGenesisHash"`
ConwayGenesisFile string `yaml:"ConwayGenesisFile"`
ConwayGenesisHash string `yaml:"ConwayGenesisHash"`
ShelleyGenesisFile string `yaml:"ShelleyGenesisFile"`
ShelleyGenesisHash string `yaml:"ShelleyGenesisHash"`
// TODO: add more fields from cardano-node config as we need them
}

func NewCardanoNodeConfigFromReader(r io.Reader) (*CardanoNodeConfig, error) {
var ret CardanoNodeConfig
dec := yaml.NewDecoder(r)
if err := dec.Decode(&ret); err != nil {
return nil, err
}
return &ret, nil
}

func NewCardanoNodeConfigFromFile(file string) (*CardanoNodeConfig, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
c, err := NewCardanoNodeConfigFromReader(f)
if err != nil {
return nil, err
}
c.path = path.Dir(file)
return c, nil
}

// ByronGenesis loads and returns the Byron genesis config specified in the node config
func (c *CardanoNodeConfig) ByronGenesis() (*byron.ByronGenesis, error) {
tmpPath := path.Join(c.path, c.ByronGenesisFile)
// TODO: check genesis file hash
ret, err := byron.NewByronGenesisFromFile(tmpPath)
if err != nil {
return nil, err
}
return &ret, err
}

// ShelleyGenesis loads and returns the Shelley genesis config specified in the node config
func (c *CardanoNodeConfig) ShelleyGenesis() (*shelley.ShelleyGenesis, error) {
tmpPath := path.Join(c.path, c.ShelleyGenesisFile)
// TODO: check genesis file hash
ret, err := shelley.NewShelleyGenesisFromFile(tmpPath)
if err != nil {
return nil, err
}
return &ret, err
}

// AlonzoGenesis loads and returns the Alonzo genesis config specified in the node config
func (c *CardanoNodeConfig) AlonzoGenesis() (*alonzo.AlonzoGenesis, error) {
tmpPath := path.Join(c.path, c.AlonzoGenesisFile)
// TODO: check genesis file hash
ret, err := alonzo.NewAlonzoGenesisFromFile(tmpPath)
if err != nil {
return nil, err
}
return &ret, err
}

// ConwayGenesis loads and returns the Conway genesis config specified in the node config
func (c *CardanoNodeConfig) ConwayGenesis() (*conway.ConwayGenesis, error) {
tmpPath := path.Join(c.path, c.ConwayGenesisFile)
// TODO: check genesis file hash
ret, err := conway.NewConwayGenesisFromFile(tmpPath)
if err != nil {
return nil, err
}
return &ret, err
}
87 changes: 87 additions & 0 deletions config/cardano/node_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2024 Blink Labs Software
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cardano

import (
"path"
"reflect"
"testing"
)

const (
testDataDir = "testdata"
)

var expectedCardanoNodeConfig = &CardanoNodeConfig{
path: testDataDir,
AlonzoGenesisFile: "alonzo-genesis.json",
AlonzoGenesisHash: "7e94a15f55d1e82d10f09203fa1d40f8eede58fd8066542cf6566008068ed874",
ByronGenesisFile: "byron-genesis.json",
ByronGenesisHash: "83de1d7302569ad56cf9139a41e2e11346d4cb4a31c00142557b6ab3fa550761",
ConwayGenesisFile: "conway-genesis.json",
ConwayGenesisHash: "9cc5084f02e27210eacba47af0872e3dba8946ad9460b6072d793e1d2f3987ef",
ShelleyGenesisFile: "shelley-genesis.json",
ShelleyGenesisHash: "363498d1024f84bb39d3fa9593ce391483cb40d479b87233f868d6e57c3a400d",
}

func TestCardanoNodeConfig(t *testing.T) {
tmpPath := path.Join(
testDataDir,
"config.json",
)
cfg, err := NewCardanoNodeConfigFromFile(tmpPath)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(cfg, expectedCardanoNodeConfig) {
t.Fatalf("did not get expected object\n got: %#v\n wanted: %#v\n", cfg, expectedCardanoNodeConfig)
}
t.Run("Byron genesis", func(t *testing.T) {
g, err := cfg.ByronGenesis()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if g == nil {
t.Fatalf("got nil instead of ByronGenesis")
}
})
t.Run("Shelley genesis", func(t *testing.T) {
g, err := cfg.ShelleyGenesis()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if g == nil {
t.Fatalf("got nil instead of ShelleyGenesis")
}
})
t.Run("Alonzo genesis", func(t *testing.T) {
g, err := cfg.AlonzoGenesis()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if g == nil {
t.Fatalf("got nil instead of AlonzoGenesis")
}
})
t.Run("Conway genesis", func(t *testing.T) {
g, err := cfg.ConwayGenesis()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if g == nil {
t.Fatalf("got nil instead of ConwayGenesis")
}
})
}
1 change: 1 addition & 0 deletions config/cardano/testdata
Loading

0 comments on commit 177fd97

Please sign in to comment.