diff --git a/node/full.go b/node/full.go index d97d4772431..5a6dd0601f4 100644 --- a/node/full.go +++ b/node/full.go @@ -369,7 +369,7 @@ func (n *FullNode) newHeaderValidator() p2p.GossipValidator { func (n *FullNode) newFraudProofValidator() p2p.GossipValidator { return func(fraudProofMsg *p2p.GossipMessage) bool { n.Logger.Debug("fraud proof received", "from", fraudProofMsg.From, "bytes", len(fraudProofMsg.Data)) - var fraudProof abci.FraudProof + fraudProof := abci.FraudProof{} err := fraudProof.Unmarshal(fraudProofMsg.Data) if err != nil { n.Logger.Error("failed to deserialize fraud proof", "error", err) diff --git a/node/light.go b/node/light.go index a8ce6ad395b..a95cacb28e4 100644 --- a/node/light.go +++ b/node/light.go @@ -1,20 +1,115 @@ package node import ( + "context" + + ds "github.com/ipfs/go-datastore" + "github.com/libp2p/go-libp2p/core/crypto" + abciclient "github.com/tendermint/tendermint/abci/client" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/service" rpcclient "github.com/tendermint/tendermint/rpc/client" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/rollkit/rollkit/config" + "github.com/rollkit/rollkit/p2p" + "github.com/rollkit/rollkit/store" ) var _ Node = &LightNode{} type LightNode struct { service.BaseService + + P2P *p2p.Client + + app abciclient.Client + + ctx context.Context } -func (n *LightNode) GetClient() rpcclient.Client { - return NewLightClient(n) +func (ln *LightNode) GetClient() rpcclient.Client { + return NewLightClient(ln) +} + +func newLightNode( + ctx context.Context, + conf config.NodeConfig, + p2pKey crypto.PrivKey, + appClient abciclient.Client, + genesis *tmtypes.GenesisDoc, + logger log.Logger, +) (*LightNode, error) { + datastore, err := openDatastore(conf, logger) + if err != nil { + return nil, err + } + client, err := p2p.NewClient(conf.P2P, p2pKey, genesis.ChainID, datastore, logger.With("module", "p2p")) + if err != nil { + return nil, err + } + + node := &LightNode{ + P2P: client, + app: appClient, + ctx: ctx, + } + + node.P2P.SetTxValidator(node.falseValidator()) + node.P2P.SetHeaderValidator(node.falseValidator()) + node.P2P.SetFraudProofValidator(node.newFraudProofValidator()) + + node.BaseService = *service.NewBaseService(logger, "LightNode", node) + + return node, nil } -func newLightNode() (Node, error) { - return &LightNode{}, nil +func openDatastore(conf config.NodeConfig, logger log.Logger) (ds.TxnDatastore, error) { + if conf.RootDir == "" && conf.DBPath == "" { // this is used for testing + logger.Info("WARNING: working in in-memory mode") + return store.NewDefaultInMemoryKVStore() + } + return store.NewDefaultKVStore(conf.RootDir, conf.DBPath, "rollkit-light") +} + +func (ln *LightNode) OnStart() error { + if err := ln.P2P.Start(ln.ctx); err != nil { + return err + } + + return nil +} + +// Dummy validator that always returns a callback function with boolean `false` +func (ln *LightNode) falseValidator() p2p.GossipValidator { + return func(*p2p.GossipMessage) bool { + return false + } +} + +func (ln *LightNode) newFraudProofValidator() p2p.GossipValidator { + return func(fraudProofMsg *p2p.GossipMessage) bool { + ln.Logger.Info("fraud proof received", "from", fraudProofMsg.From, "bytes", len(fraudProofMsg.Data)) + fraudProof := abci.FraudProof{} + err := fraudProof.Unmarshal(fraudProofMsg.Data) + if err != nil { + ln.Logger.Error("failed to deserialize fraud proof", "error", err) + return false + } + + resp, err := ln.app.VerifyFraudProofSync(abci.RequestVerifyFraudProof{ + FraudProof: &fraudProof, + ExpectedValidAppHash: fraudProof.ExpectedValidAppHash, + }) + if err != nil { + return false + } + + if resp.Success { + panic("received valid fraud proof! halting light client") + } + + return false + } } diff --git a/node/node.go b/node/node.go index dc6aff31933..2960d5b7761 100644 --- a/node/node.go +++ b/node/node.go @@ -40,6 +40,13 @@ func NewNode( logger, ) } else { - return newLightNode() + return newLightNode( + ctx, + conf, + p2pKey, + appClient, + genesis, + logger, + ) } }