diff --git a/README.md b/README.md index 35be42a42e5..90abd63742e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ A modular framework for rollups, with an ABCI-compatible client interface. [![Go Report Card](https://goreportcard.com/badge/github.com/rollkit/rollkit)](https://goreportcard.com/report/github.com/rollkit/rollkit) [![codecov](https://codecov.io/gh/rollkit/rollkit/branch/main/graph/badge.svg?token=CWGA4RLDS9)](https://codecov.io/gh/rollkit/rollkit) [![GoDoc](https://godoc.org/github.com/rollkit/rollkit?status.svg)](https://godoc.org/github.com/rollkit/rollkit) -[![Twitter Follow](https://img.shields.io/twitter/follow/CelestiaOrg?style=social)](https://twitter.com/CelestiaOrg) ## Building From Source diff --git a/go.mod b/go.mod index 490d596b2f6..8c0e9accc73 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/celestiaorg/go-cnc v0.3.0 + github.com/celestiaorg/go-fraud v0.1.0 github.com/celestiaorg/go-header v0.2.6 github.com/dgraph-io/badger/v3 v3.2103.5 github.com/go-kit/kit v0.12.0 diff --git a/go.sum b/go.sum index 20e6c868182..a6258fd5108 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/celestiaorg/go-cnc v0.3.0 h1:eAVPNHGpx+2sBO7NZyQ1+VW8rzf6W4FQDlSq6aqSTsM= github.com/celestiaorg/go-cnc v0.3.0/go.mod h1:zYzvHudSd1iNPuHBMyvZ1YvWou5aT9JXgtch9Tkaf70= +github.com/celestiaorg/go-fraud v0.1.0 h1:v6mZvlmf2J5ELZfPnrtmmOvKbaYIUs/erDWPO8NbZyY= +github.com/celestiaorg/go-fraud v0.1.0/go.mod h1:yoNM35cKMAkt5Mi/Qx3Wi9bnPilLi8n6RpHZVglTUDs= github.com/celestiaorg/go-header v0.2.6 h1:f1Mlyu+EfDpkuzO3SWU5dow+ga2vLQ7hNuvsOe//z64= github.com/celestiaorg/go-header v0.2.6/go.mod h1:i9OpY70+PJ1xPw1IgMfF0Pk6vBD6VWPmjY3bgubJBcU= github.com/celestiaorg/go-libp2p-messenger v0.2.0 h1:/0MuPDcFamQMbw9xTZ73yImqgTO3jHV7wKHvWD/Irao= diff --git a/node/full.go b/node/full.go index bf4e39bf4a1..c950bbad1fd 100644 --- a/node/full.go +++ b/node/full.go @@ -7,6 +7,8 @@ import ( "errors" "fmt" + "github.com/celestiaorg/go-fraud/fraudserv" + "github.com/celestiaorg/go-header" ds "github.com/ipfs/go-datastore" ktds "github.com/ipfs/go-datastore/keytransform" "github.com/libp2p/go-libp2p/core/crypto" @@ -32,6 +34,7 @@ import ( "github.com/rollkit/rollkit/state/txindex" "github.com/rollkit/rollkit/state/txindex/kv" "github.com/rollkit/rollkit/store" + "github.com/rollkit/rollkit/types" ) // prefixes used in KV store to separate main node data from DALC data @@ -76,7 +79,9 @@ type FullNode struct { BlockIndexer indexer.BlockIndexer IndexerService *txindex.IndexerService - hExService *HeaderExchangeService + hExService *HeaderExchangeService + fraudService *fraudserv.ProofService + proofServiceFactory ProofServiceFactory // keep context here only because of API compatibility // - it's used in `OnStart` (defined in service.Service interface) @@ -161,27 +166,38 @@ func newFullNode( return nil, fmt.Errorf("HeaderExchangeService initialization error: %w", err) } + fraudProofFactory := NewProofServiceFactory( + client, + func(ctx context.Context, u uint64) (header.Header, error) { + return headerExchangeService.headerStore.GetByHeight(ctx, u) + }, + mainKV, + true, + types.StateFraudProofType, + ) + ctx, cancel := context.WithCancel(ctx) node := &FullNode{ - proxyApp: proxyApp, - eventBus: eventBus, - genesis: genesis, - conf: conf, - P2P: client, - blockManager: blockManager, - dalc: dalc, - Mempool: mp, - mempoolIDs: mpIDs, - incomingTxCh: make(chan *p2p.GossipMessage), - Store: s, - TxIndexer: txIndexer, - IndexerService: indexerService, - BlockIndexer: blockIndexer, - hExService: headerExchangeService, - ctx: ctx, - cancel: cancel, - DoneBuildingBlock: doneBuildingChannel, + proxyApp: proxyApp, + eventBus: eventBus, + genesis: genesis, + conf: conf, + P2P: client, + blockManager: blockManager, + dalc: dalc, + Mempool: mp, + mempoolIDs: mpIDs, + incomingTxCh: make(chan *p2p.GossipMessage), + Store: s, + TxIndexer: txIndexer, + IndexerService: indexerService, + BlockIndexer: blockIndexer, + hExService: headerExchangeService, + proofServiceFactory: fraudProofFactory, + ctx: ctx, + cancel: cancel, + DoneBuildingBlock: doneBuildingChannel, } node.BaseService = *service.NewBaseService(logger, "Node", node) @@ -269,6 +285,14 @@ func (n *FullNode) OnStart() error { if err = n.dalc.Start(); err != nil { return fmt.Errorf("error while starting data availability layer client: %w", err) } + + // since p2p pubsub and host are required to create ProofService, + // we have to delay the construction until Start and use the help of ProofServiceFactory + n.fraudService = n.proofServiceFactory.CreateProofService() + if err = n.fraudService.Start(n.ctx); err != nil { + return fmt.Errorf("error while starting fraud exchange service: %w", err) + } + if n.conf.Aggregator { n.Logger.Info("working in aggregator mode", "block time", n.conf.BlockTime) go n.blockManager.AggregationLoop(n.ctx, n.conf.LazyAggregator) diff --git a/node/header_exchange.go b/node/header_exchange.go index 8776c61f301..90e17d79aa8 100644 --- a/node/header_exchange.go +++ b/node/header_exchange.go @@ -218,7 +218,7 @@ func newP2PExchange( ) (*goheaderp2p.Exchange[*types.SignedHeader], error) { opts = append(opts, goheaderp2p.WithNetworkID[goheaderp2p.ClientParameters](network), - goheaderp2p.WithChainID[goheaderp2p.ClientParameters](chainID), + goheaderp2p.WithChainID(chainID), ) return goheaderp2p.NewExchange[*types.SignedHeader](host, peers, conngater, opts...) } diff --git a/node/light.go b/node/light.go index dabe44fcf68..fde87c73051 100644 --- a/node/light.go +++ b/node/light.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/celestiaorg/go-fraud/fraudserv" + "github.com/celestiaorg/go-header" ds "github.com/ipfs/go-datastore" "github.com/libp2p/go-libp2p/core/crypto" abci "github.com/tendermint/tendermint/abci/types" @@ -17,6 +19,7 @@ import ( "github.com/rollkit/rollkit/config" "github.com/rollkit/rollkit/p2p" "github.com/rollkit/rollkit/store" + "github.com/rollkit/rollkit/types" ) var _ Node = &LightNode{} @@ -28,7 +31,9 @@ type LightNode struct { proxyApp proxy.AppConns - hExService *HeaderExchangeService + hExService *HeaderExchangeService + fraudService *fraudserv.ProofService + proofServiceFactory ProofServiceFactory ctx context.Context cancel context.CancelFunc @@ -67,14 +72,25 @@ func newLightNode( return nil, fmt.Errorf("HeaderExchangeService initialization error: %w", err) } + fraudProofFactory := NewProofServiceFactory( + client, + func(ctx context.Context, u uint64) (header.Header, error) { + return headerExchangeService.headerStore.GetByHeight(ctx, u) + }, + datastore, + true, + types.StateFraudProofType, + ) + ctx, cancel := context.WithCancel(ctx) node := &LightNode{ - P2P: client, - proxyApp: proxyApp, - hExService: headerExchangeService, - cancel: cancel, - ctx: ctx, + P2P: client, + proxyApp: proxyApp, + hExService: headerExchangeService, + proofServiceFactory: fraudProofFactory, + cancel: cancel, + ctx: ctx, } node.P2P.SetTxValidator(node.falseValidator()) @@ -103,6 +119,11 @@ func (ln *LightNode) OnStart() error { return fmt.Errorf("error while starting header exchange service: %w", err) } + ln.fraudService = ln.proofServiceFactory.CreateProofService() + if err := ln.fraudService.Start(ln.ctx); err != nil { + return fmt.Errorf("error while starting fraud exchange service: %w", err) + } + return nil } diff --git a/node/proof_service_factory.go b/node/proof_service_factory.go new file mode 100644 index 00000000000..fbb7a9c7635 --- /dev/null +++ b/node/proof_service_factory.go @@ -0,0 +1,38 @@ +package node + +import ( + "github.com/celestiaorg/go-fraud" + "github.com/celestiaorg/go-fraud/fraudserv" + "github.com/ipfs/go-datastore" + + "github.com/rollkit/rollkit/p2p" +) + +type ProofServiceFactory struct { + client *p2p.Client + getter fraud.HeaderFetcher + ds datastore.Datastore + syncerEnabled bool + proofType fraud.ProofType +} + +func NewProofServiceFactory(c *p2p.Client, getter fraud.HeaderFetcher, ds datastore.Datastore, syncerEnabled bool, proofType fraud.ProofType) ProofServiceFactory { + return ProofServiceFactory{ + client: c, + getter: getter, + ds: ds, + syncerEnabled: syncerEnabled, + proofType: proofType, + } +} + +func (factory *ProofServiceFactory) CreateProofService() *fraudserv.ProofService { + return fraudserv.NewProofService( + factory.client.PubSub(), + factory.client.Host(), + factory.getter, + factory.ds, + factory.syncerEnabled, + factory.proofType.String(), + ) +} diff --git a/types/state_fraud_proof.go b/types/state_fraud_proof.go new file mode 100644 index 00000000000..4c5e8fbfd6f --- /dev/null +++ b/types/state_fraud_proof.go @@ -0,0 +1,47 @@ +package types + +import ( + "github.com/celestiaorg/go-header" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/celestiaorg/go-fraud" +) + +// Implements Proof interface from https://github.com/celestiaorg/go-fraud/ + +const StateFraudProofType fraud.ProofType = "state-fraud" + +type StateFraudProof struct { + abci.FraudProof +} + +func init() { + fraud.Register(&StateFraudProof{}) +} + +func (fp *StateFraudProof) Type() fraud.ProofType { + return StateFraudProofType +} + +func (fp *StateFraudProof) HeaderHash() []byte { + return fp.FraudulentBeginBlock.Hash +} + +func (fp *StateFraudProof) Height() uint64 { + return uint64(fp.BlockHeight) +} + +func (fp *StateFraudProof) Validate(header.Header) error { + // TODO (ganesh): fill this later + return nil +} + +func (fp *StateFraudProof) MarshalBinary() (data []byte, err error) { + return fp.Marshal() +} + +func (fp *StateFraudProof) UnmarshalBinary(data []byte) error { + return fp.Unmarshal(data) +} + +var _ fraud.Proof = &StateFraudProof{}