diff --git a/.github/workflows/build-evmos.yml b/.github/workflows/build-evmos.yml index 04c927a30..c9484716b 100644 --- a/.github/workflows/build-evmos.yml +++ b/.github/workflows/build-evmos.yml @@ -3,12 +3,10 @@ name: build-evmos on: push: branches: - - '**' - tags: - - 'v*.*.*' + - main pull_request: - branches: - - 'main' + release: + types: [published] workflow_dispatch: env: @@ -26,7 +24,7 @@ jobs: - name: "Checkout source code" uses: "actions/checkout@v3" - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 - name: up a level diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8fe1c6692..6593b96fa 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: golangci-lint +name: Linters on: push: tags: @@ -6,13 +6,14 @@ on: branches: - main pull_request: + jobs: golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: golangci-lint @@ -38,3 +39,12 @@ jobs: # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. # skip-build-cache: true + markdownlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: markdownlint-cli + uses: nosborn/github-action-markdown-cli@v3.0.1 + with: + files: . + config-file: .markdownlint.yaml \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fbdbb2b90..7cd0ac7c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: 1.17 diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 000000000..7d2cc8570 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,7 @@ +default: true +MD010: + code_blocks: false +MD013: false +MD024: + allow_different_nesting: true + diff --git a/CHANGELOG.md b/CHANGELOG.md index 75aa2491d..653ea34b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Minor bugfix release, to ensure that Optimint uses the same version of gRPC as Cosmos SDK. ### BUG FIXES + - Use google.golang.org/grpc v1.33.2 to be compatible with cosmos-sdk ([#315](https://github.com/celestiaorg/optimint/pull/315)) [@jbowen93](https://github.com/jbowen93/) - Make TestValidatorSetHandling even more stable ([#314](https://github.com/celestiaorg/optimint/pull/314)) [@tzdybal](https://github.com/tzdybal/) @@ -14,6 +15,7 @@ This is the first Optimint release. Optimint supports all ABCI methods and all Tendermint RPCs. ### FEATURES + - Minimal implementation of ConsensusParams method ([#292](https://github.com/celestiaorg/optimint/pull/292)) [@tzdybal](https://github.com/tzdybal/) - Implement GenesisChunked method ([#287](https://github.com/celestiaorg/optimint/pull/287)) [@mauriceLC92](https://github.com/mauriceLC92/) - Minimalistic validator set handling ([#286](https://github.com/celestiaorg/optimint/pull/286)) [@tzdybal](https://github.com/tzdybal/) @@ -61,6 +63,7 @@ Optimint supports all ABCI methods and all Tendermint RPCs. - Add design doc to readme ([#9](https://github.com/celestiaorg/optimint/pull/9)) [@musalbas](https://github.com/musalbas/) ### IMPROVEMENTS + - Remove extra variable ([#280](https://github.com/celestiaorg/optimint/pull/280)) [@Raneet10](https://github.com/Raneet10/) - Replace tm-db dependency with store package ([#268](https://github.com/celestiaorg/optimint/pull/268)) [@tzdybal](https://github.com/tzdybal/) - Use enum instead of strings for DB type ([#259](https://github.com/celestiaorg/optimint/pull/259)) [@adlerjohn](https://github.com/adlerjohn/) @@ -87,6 +90,7 @@ Optimint supports all ABCI methods and all Tendermint RPCs. - Use addresses in multiaddr format. ([#19](https://github.com/celestiaorg/optimint/pull/19)) [@tzdybal](https://github.com/tzdybal/) ### BUG FIXES + - fix: make `TestValidatorSetHandling` stable ([#313](https://github.com/celestiaorg/optimint/pull/313)) [@tzdybal](https://github.com/tzdybal/) - Fix linter on `main` ([#308](https://github.com/celestiaorg/optimint/pull/308)) [@tzdybal](https://github.com/tzdybal/) - Fix multiple bugs for Ethermint ([#305](https://github.com/celestiaorg/optimint/pull/305)) [@tzdybal](https://github.com/tzdybal/) @@ -101,4 +105,4 @@ Optimint supports all ABCI methods and all Tendermint RPCs. - Fix typos in node/node.go ([#86](https://github.com/celestiaorg/optimint/pull/86)) [@tzdybal](https://github.com/tzdybal/) - Fixing linter errors ([#55](https://github.com/celestiaorg/optimint/pull/55)) [@tzdybal](https://github.com/tzdybal/) - Add peer discovery ([#17](https://github.com/celestiaorg/optimint/pull/17)) [@tzdybal](https://github.com/tzdybal/) -- P2P bootstrapping ([#14](https://github.com/celestiaorg/optimint/pull/14)) [@tzdybal](https://github.com/tzdybal/) \ No newline at end of file +- P2P bootstrapping ([#14](https://github.com/celestiaorg/optimint/pull/14)) [@tzdybal](https://github.com/tzdybal/) diff --git a/README.md b/README.md index 11e99c68c..5fe8f101c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ABCI-client implementation for Optimistic Rollups. -Design document: https://docs.google.com/document/d/12gZow_JTJjRrmaD2mNTmYniLhyxVLSyDd7Fbxo5UnA8/edit?usp=sharing +Design document: [![build-and-test](https://github.com/celestiaorg/optimint/actions/workflows/test.yml/badge.svg)](https://github.com/celestiaorg/optimint/actions/workflows/test.yml) [![golangci-lint](https://github.com/celestiaorg/optimint/actions/workflows/lint.yml/badge.svg)](https://github.com/celestiaorg/optimint/actions/workflows/lint.yml) diff --git a/block/manager.go b/block/manager.go index 6a6a61d1e..13637cdaf 100644 --- a/block/manager.go +++ b/block/manager.go @@ -3,6 +3,7 @@ package block import ( "context" "fmt" + "sync" "sync/atomic" "time" @@ -12,6 +13,7 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/proxy" tmtypes "github.com/tendermint/tendermint/types" + "go.uber.org/multierr" "github.com/celestiaorg/optimint/config" "github.com/celestiaorg/optimint/da" @@ -22,6 +24,9 @@ import ( "github.com/celestiaorg/optimint/types" ) +// defaultDABlockTime is used only if DABlockTime is not configured for manager +const defaultDABlockTime = 30 * time.Second + // Manager is responsible for aggregating transactions into blocks. type Manager struct { lastState state.State @@ -36,15 +41,21 @@ type Manager struct { dalc da.DataAvailabilityLayerClient retriever da.BlockRetriever + // daHeight is the height of the latest processed DA block + daHeight uint64 HeaderOutCh chan *types.Header HeaderInCh chan *types.Header syncTarget uint64 blockInCh chan *types.Block - retrieveCh chan uint64 syncCache map[uint64]*types.Block + // retrieveMtx is used by retrieveCond + retrieveMtx *sync.Mutex + // retrieveCond is used to notify sync goroutine (SyncLoop) that it needs to retrieve data + retrieveCond *sync.Cond + logger log.Logger } @@ -72,12 +83,20 @@ func NewManager( if err != nil { return nil, err } + if s.DAHeight < conf.DAStartHeight { + s.DAHeight = conf.DAStartHeight + } proposerAddress, err := getAddress(proposerKey) if err != nil { return nil, err } + if conf.DABlockTime == 0 { + logger.Info("WARNING: using default DA block time", "DABlockTime", defaultDABlockTime) + conf.DABlockTime = defaultDABlockTime + } + exec := state.NewBlockExecutor(proposerAddress, conf.NamespaceID, genesis.ChainID, mempool, proxyApp, eventBus, logger) if s.LastBlockHeight+1 == genesis.InitialHeight { res, err := exec.InitChain(genesis) @@ -100,13 +119,16 @@ func NewManager( executor: exec, dalc: dalc, retriever: dalc.(da.BlockRetriever), // TODO(tzdybal): do it in more gentle way (after MVP) - HeaderOutCh: make(chan *types.Header), - HeaderInCh: make(chan *types.Header), - blockInCh: make(chan *types.Block), - retrieveCh: make(chan uint64), + daHeight: s.DAHeight, + // channels are buffered to avoid blocking on input/output operations, buffer sizes are arbitrary + HeaderOutCh: make(chan *types.Header, 100), + HeaderInCh: make(chan *types.Header, 100), + blockInCh: make(chan *types.Block, 100), + retrieveMtx: new(sync.Mutex), syncCache: make(map[uint64]*types.Block), logger: logger, } + agg.retrieveCond = sync.NewCond(agg.retrieveMtx) return agg, nil } @@ -142,8 +164,11 @@ func (m *Manager) AggregationLoop(ctx context.Context) { } func (m *Manager) SyncLoop(ctx context.Context) { + daTicker := time.NewTicker(m.conf.DABlockTime) for { select { + case <-daTicker.C: + m.retrieveCond.Signal() case header := <-m.HeaderInCh: m.logger.Debug("block header received", "height", header.Height, "hash", header.Hash()) newHeight := header.Height @@ -153,7 +178,7 @@ func (m *Manager) SyncLoop(ctx context.Context) { // it's handled gently in RetrieveLoop if newHeight > currentHeight { atomic.StoreUint64(&m.syncTarget, newHeight) - m.retrieveCh <- newHeight + m.retrieveCond.Signal() } case block := <-m.blockInCh: m.logger.Debug("block body retrieved from DALC", @@ -161,6 +186,7 @@ func (m *Manager) SyncLoop(ctx context.Context) { "hash", block.Hash(), ) m.syncCache[block.Header.Height] = block + m.retrieveCond.Signal() currentHeight := m.store.Height() // TODO(tzdybal): maybe store a copy in memory b1, ok1 := m.syncCache[currentHeight+1] b2, ok2 := m.syncCache[currentHeight+2] @@ -181,6 +207,7 @@ func (m *Manager) SyncLoop(ctx context.Context) { continue } + newState.DAHeight = atomic.LoadUint64(&m.daHeight) m.lastState = newState err = m.store.UpdateState(m.lastState) if err != nil { @@ -195,14 +222,36 @@ func (m *Manager) SyncLoop(ctx context.Context) { } } +// RetrieveLoop is responsible for interacting with DA layer. func (m *Manager) RetrieveLoop(ctx context.Context) { + // waitCh is used to signal the retrieve loop, that it should process next blocks + // retrieveCond can be signalled in completely async manner, and goroutine below + // works as some kind of "buffer" for those signals + waitCh := make(chan interface{}) + go func() { + for { + m.retrieveMtx.Lock() + m.retrieveCond.Wait() + waitCh <- nil + m.retrieveMtx.Unlock() + if ctx.Err() != nil { + return + } + } + }() + for { select { - case <-m.retrieveCh: - target := atomic.LoadUint64(&m.syncTarget) - for h := m.store.Height() + 1; h <= target; h++ { - m.logger.Debug("trying to retrieve block from DALC", "height", h) - m.mustRetrieveBlock(ctx, h) + case <-waitCh: + for { + daHeight := atomic.LoadUint64(&m.daHeight) + m.logger.Debug("retrieve", "daHeight", daHeight) + err := m.processNextDABlock() + if err != nil { + m.logger.Error("failed to retrieve block from DALC", "daHeight", daHeight, "errors", err.Error()) + break + } + atomic.AddUint64(&m.daHeight, 1) } case <-ctx.Done(): return @@ -210,35 +259,38 @@ func (m *Manager) RetrieveLoop(ctx context.Context) { } } -func (m *Manager) mustRetrieveBlock(ctx context.Context, height uint64) { +func (m *Manager) processNextDABlock() error { // TODO(tzdybal): extract configuration option maxRetries := 10 + daHeight := atomic.LoadUint64(&m.daHeight) + var err error + m.logger.Debug("trying to retrieve block from DA", "daHeight", daHeight) for r := 0; r < maxRetries; r++ { - err := m.fetchBlock(ctx, height) - if err == nil { - return + blockResp, fetchErr := m.fetchBlock(daHeight) + if fetchErr != nil { + err = multierr.Append(err, fetchErr) + time.Sleep(100 * time.Millisecond) + } else { + for _, block := range blockResp.Blocks { + m.blockInCh <- block + } + return nil } - // TODO(tzdybal): configuration option - // TODO(tzdybal): exponential backoff - time.Sleep(100 * time.Millisecond) } - // TODO(tzdybal): this is only temporary solution, for MVP - panic("failed to retrieve block with DALC") + return err } -func (m *Manager) fetchBlock(ctx context.Context, height uint64) error { +func (m *Manager) fetchBlock(daHeight uint64) (da.ResultRetrieveBlocks, error) { var err error - blockRes := m.retriever.RetrieveBlock(height) + blockRes := m.retriever.RetrieveBlocks(daHeight) switch blockRes.Code { - case da.StatusSuccess: - m.blockInCh <- blockRes.Block case da.StatusError: err = fmt.Errorf("failed to retrieve block: %s", blockRes.Message) case da.StatusTimeout: err = fmt.Errorf("timeout during retrieve block: %s", blockRes.Message) } - return err + return blockRes, err } func (m *Manager) getRemainingSleep(start time.Time) time.Duration { @@ -305,6 +357,7 @@ func (m *Manager) publishBlock(ctx context.Context) error { return err } + newState.DAHeight = atomic.LoadUint64(&m.daHeight) m.lastState = newState err = m.store.UpdateState(m.lastState) if err != nil { @@ -320,6 +373,7 @@ func (m *Manager) publishBlock(ctx context.Context) error { } func (m *Manager) broadcastBlock(ctx context.Context, block *types.Block) error { + m.logger.Debug("submitting block to DA layer", "height", block.Header.Height) res := m.dalc.SubmitBlock(block) if res.Code != da.StatusSuccess { return fmt.Errorf("DA layer submission failed: %s", res.Message) diff --git a/config/config.go b/config/config.go index da4fc6f09..fd6abfb65 100644 --- a/config/config.go +++ b/config/config.go @@ -32,8 +32,13 @@ type NodeConfig struct { // BlockManagerConfig consists of all parameters required by BlockManagerConfig type BlockManagerConfig struct { - BlockTime time.Duration `mapstructure:"block_time"` - NamespaceID [8]byte `mapstructure:"namespace_id"` + // BlockTime defines how often new blocks are produced + BlockTime time.Duration `mapstructure:"block_time"` + // DABlockTime informs about block time of underlying data availability layer + DABlockTime time.Duration `mapstructure:"da_block_time"` + // DAStartHeight allows skipping first DAStartHeight-1 blocks when querying for blocks. + DAStartHeight uint64 `mapstructure:"da_start_height"` + NamespaceID [8]byte `mapstructure:"namespace_id"` } func (nc *NodeConfig) GetViperConfig(v *viper.Viper) error { diff --git a/da/da.go b/da/da.go index 769f343af..ed32d94fb 100644 --- a/da/da.go +++ b/da/da.go @@ -25,6 +25,8 @@ type DAResult struct { Code StatusCode // Message may contain DA layer specific information (like DA block height/hash, detailed error message, etc) Message string + // DAHeight informs about a height on Data Availability Layer for given result. + DAHeight uint64 } // ResultSubmitBlock contains information returned from DA layer after block submission. @@ -43,11 +45,11 @@ type ResultCheckBlock struct { DataAvailable bool } -type ResultRetrieveBlock struct { +type ResultRetrieveBlocks struct { DAResult // Block is the full block retrieved from Data Availability Layer. // If Code is not equal to StatusSuccess, it has to be nil. - Block *types.Block + Blocks []*types.Block } // DataAvailabilityLayerClient defines generic interface for DA layer block submission. @@ -65,12 +67,12 @@ type DataAvailabilityLayerClient interface { SubmitBlock(block *types.Block) ResultSubmitBlock // CheckBlockAvailability queries DA layer to check data availability of block corresponding to given header. - CheckBlockAvailability(header *types.Header) ResultCheckBlock + CheckBlockAvailability(dataLayerHeight uint64) ResultCheckBlock } // BlockRetriever is additional interface that can be implemented by Data Availability Layer Client that is able to retrieve // block data from DA layer. This gives the ability to use it for block synchronization. type BlockRetriever interface { - // RetrieveBlock returns block at given height from data availability layer. - RetrieveBlock(height uint64) ResultRetrieveBlock + // RetrieveBlocks returns blocks at given data layer height from data availability layer. + RetrieveBlocks(dataLayerHeight uint64) ResultRetrieveBlocks } diff --git a/da/grpc/grpc.go b/da/grpc/grpc.go index 21e0ff6ac..f27063794 100644 --- a/da/grpc/grpc.go +++ b/da/grpc/grpc.go @@ -75,12 +75,16 @@ func (d *DataAvailabilityLayerClient) SubmitBlock(block *types.Block) da.ResultS } } return da.ResultSubmitBlock{ - DAResult: da.DAResult{Code: da.StatusCode(resp.Result.Code), Message: resp.Result.Message}, + DAResult: da.DAResult{ + Code: da.StatusCode(resp.Result.Code), + Message: resp.Result.Message, + DAHeight: resp.Result.DataLayerHeight, + }, } } -func (d *DataAvailabilityLayerClient) CheckBlockAvailability(header *types.Header) da.ResultCheckBlock { - resp, err := d.client.CheckBlockAvailability(context.TODO(), &dalc.CheckBlockAvailabilityRequest{Header: header.ToProto()}) +func (d *DataAvailabilityLayerClient) CheckBlockAvailability(dataLayerHeight uint64) da.ResultCheckBlock { + resp, err := d.client.CheckBlockAvailability(context.TODO(), &dalc.CheckBlockAvailabilityRequest{DataLayerHeight: dataLayerHeight}) if err != nil { return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} } @@ -90,19 +94,27 @@ func (d *DataAvailabilityLayerClient) CheckBlockAvailability(header *types.Heade } } -func (d *DataAvailabilityLayerClient) RetrieveBlock(height uint64) da.ResultRetrieveBlock { - resp, err := d.client.RetrieveBlock(context.TODO(), &dalc.RetrieveBlockRequest{Height: height}) +func (d *DataAvailabilityLayerClient) RetrieveBlocks(dataLayerHeight uint64) da.ResultRetrieveBlocks { + resp, err := d.client.RetrieveBlocks(context.TODO(), &dalc.RetrieveBlocksRequest{DataLayerHeight: dataLayerHeight}) if err != nil { - return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} + return da.ResultRetrieveBlocks{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} } - var b types.Block - err = b.FromProto(resp.Block) - if err != nil { - return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} + blocks := make([]*types.Block, len(resp.Blocks)) + for i, block := range resp.Blocks { + var b types.Block + err = b.FromProto(block) + if err != nil { + return da.ResultRetrieveBlocks{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} + } + blocks[i] = &b } - return da.ResultRetrieveBlock{ - DAResult: da.DAResult{Code: da.StatusCode(resp.Result.Code), Message: resp.Result.Message}, - Block: &b, + return da.ResultRetrieveBlocks{ + DAResult: da.DAResult{ + Code: da.StatusCode(resp.Result.Code), + Message: resp.Result.Message, + DAHeight: dataLayerHeight, + }, + Blocks: blocks, } } diff --git a/da/grpc/mockserv/cmd/main.go b/da/grpc/mockserv/cmd/main.go index cfc30453d..b69189f15 100644 --- a/da/grpc/mockserv/cmd/main.go +++ b/da/grpc/mockserv/cmd/main.go @@ -24,7 +24,7 @@ func main() { log.Panic(err) } log.Println("Listening on:", lis.Addr()) - srv := mockserv.GetServer(kv, conf) + srv := mockserv.GetServer(kv, conf, nil) if err := srv.Serve(lis); err != nil { log.Println("error while serving:", err) } diff --git a/da/grpc/mockserv/mockserv.go b/da/grpc/mockserv/mockserv.go index aae7e5e4e..b0fc5d5d7 100644 --- a/da/grpc/mockserv/mockserv.go +++ b/da/grpc/mockserv/mockserv.go @@ -4,25 +4,32 @@ import ( "context" "os" + tmlog "github.com/tendermint/tendermint/libs/log" + "google.golang.org/grpc" + grpcda "github.com/celestiaorg/optimint/da/grpc" "github.com/celestiaorg/optimint/da/mock" "github.com/celestiaorg/optimint/store" "github.com/celestiaorg/optimint/types" "github.com/celestiaorg/optimint/types/pb/dalc" - tmlog "github.com/tendermint/tendermint/libs/log" - "google.golang.org/grpc" + "github.com/celestiaorg/optimint/types/pb/optimint" ) -func GetServer(kv store.KVStore, conf grpcda.Config) *grpc.Server { +func GetServer(kv store.KVStore, conf grpcda.Config, mockConfig []byte) *grpc.Server { logger := tmlog.NewTMLogger(os.Stdout) srv := grpc.NewServer() mockImpl := &mockImpl{} - err := mockImpl.mock.Init(nil, kv, logger) + err := mockImpl.mock.Init(mockConfig, kv, logger) if err != nil { logger.Error("failed to initialize mock DALC", "error", err) panic(err) } + err = mockImpl.mock.Start() + if err != nil { + logger.Error("failed to start mock DALC", "error", err) + panic(err) + } dalc.RegisterDALCServiceServer(srv, mockImpl) return srv } @@ -40,19 +47,15 @@ func (m *mockImpl) SubmitBlock(_ context.Context, request *dalc.SubmitBlockReque resp := m.mock.SubmitBlock(&b) return &dalc.SubmitBlockResponse{ Result: &dalc.DAResponse{ - Code: dalc.StatusCode(resp.Code), - Message: resp.Message, + Code: dalc.StatusCode(resp.Code), + Message: resp.Message, + DataLayerHeight: resp.DAHeight, }, }, nil } func (m *mockImpl) CheckBlockAvailability(_ context.Context, request *dalc.CheckBlockAvailabilityRequest) (*dalc.CheckBlockAvailabilityResponse, error) { - var h types.Header - err := h.FromProto(request.Header) - if err != nil { - return nil, err - } - resp := m.mock.CheckBlockAvailability(&h) + resp := m.mock.CheckBlockAvailability(request.DataLayerHeight) return &dalc.CheckBlockAvailabilityResponse{ Result: &dalc.DAResponse{ Code: dalc.StatusCode(resp.Code), @@ -62,13 +65,17 @@ func (m *mockImpl) CheckBlockAvailability(_ context.Context, request *dalc.Check }, nil } -func (m *mockImpl) RetrieveBlock(context context.Context, request *dalc.RetrieveBlockRequest) (*dalc.RetrieveBlockResponse, error) { - resp := m.mock.RetrieveBlock(request.Height) - return &dalc.RetrieveBlockResponse{ +func (m *mockImpl) RetrieveBlocks(context context.Context, request *dalc.RetrieveBlocksRequest) (*dalc.RetrieveBlocksResponse, error) { + resp := m.mock.RetrieveBlocks(request.DataLayerHeight) + blocks := make([]*optimint.Block, len(resp.Blocks)) + for i := range resp.Blocks { + blocks[i] = resp.Blocks[i].ToProto() + } + return &dalc.RetrieveBlocksResponse{ Result: &dalc.DAResponse{ Code: dalc.StatusCode(resp.Code), Message: resp.Message, }, - Block: resp.Block.ToProto(), + Blocks: blocks, }, nil } diff --git a/da/mock/mock.go b/da/mock/mock.go index b701acae1..1ced5dacb 100644 --- a/da/mock/mock.go +++ b/da/mock/mock.go @@ -2,7 +2,9 @@ package mock import ( "encoding/binary" - "errors" + "math/rand" + "sync/atomic" + "time" "github.com/celestiaorg/optimint/da" "github.com/celestiaorg/optimint/log" @@ -13,8 +15,16 @@ import ( // MockDataAvailabilityLayerClient is intended only for usage in tests. // It does actually ensures DA - it stores data in-memory. type MockDataAvailabilityLayerClient struct { - logger log.Logger - dalcKV store.KVStore + logger log.Logger + dalcKV store.KVStore + daHeight uint64 + config Config +} + +const DefaultBlockTime = 3 * time.Second + +type Config struct { + BlockTime time.Duration } var _ da.DataAvailabilityLayerClient = &MockDataAvailabilityLayerClient{} @@ -24,12 +34,28 @@ var _ da.BlockRetriever = &MockDataAvailabilityLayerClient{} func (m *MockDataAvailabilityLayerClient) Init(config []byte, dalcKV store.KVStore, logger log.Logger) error { m.logger = logger m.dalcKV = dalcKV + m.daHeight = 1 + if len(config) > 0 { + var err error + m.config.BlockTime, err = time.ParseDuration(string(config)) + if err != nil { + return err + } + } else { + m.config.BlockTime = DefaultBlockTime + } return nil } // Start implements DataAvailabilityLayerClient interface. func (m *MockDataAvailabilityLayerClient) Start() error { m.logger.Debug("Mock Data Availability Layer Client starting") + go func() { + for { + time.Sleep(m.config.BlockTime) + m.updateDAHeight() + } + }() return nil } @@ -43,7 +69,8 @@ func (m *MockDataAvailabilityLayerClient) Stop() error { // This should create a transaction which (potentially) // triggers a state transition in the DA layer. func (m *MockDataAvailabilityLayerClient) SubmitBlock(block *types.Block) da.ResultSubmitBlock { - m.logger.Debug("Submitting block to DA layer!", "height", block.Header.Height) + daHeight := atomic.LoadUint64(&m.daHeight) + m.logger.Debug("Submitting block to DA layer!", "height", block.Header.Height, "dataLayerHeight", daHeight) hash := block.Header.Hash() blob, err := block.MarshalBinary() @@ -51,7 +78,7 @@ func (m *MockDataAvailabilityLayerClient) SubmitBlock(block *types.Block) da.Res return da.ResultSubmitBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} } - err = m.dalcKV.Set(getKey(block.Header.Height), hash[:]) + err = m.dalcKV.Set(getKey(daHeight, block.Header.Height), hash[:]) if err != nil { return da.ResultSubmitBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} } @@ -62,47 +89,64 @@ func (m *MockDataAvailabilityLayerClient) SubmitBlock(block *types.Block) da.Res return da.ResultSubmitBlock{ DAResult: da.DAResult{ - Code: da.StatusSuccess, - Message: "OK", + Code: da.StatusSuccess, + Message: "OK", + DAHeight: daHeight, }, } } // CheckBlockAvailability queries DA layer to check data availability of block corresponding to given header. -func (m *MockDataAvailabilityLayerClient) CheckBlockAvailability(header *types.Header) da.ResultCheckBlock { - hash := header.Hash() - _, err := m.dalcKV.Get(hash[:]) - if errors.Is(err, store.ErrKeyNotFound) { - return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, DataAvailable: false} - } - if err != nil { - return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}, DataAvailable: false} - } - return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, DataAvailable: true} +func (m *MockDataAvailabilityLayerClient) CheckBlockAvailability(dataLayerHeight uint64) da.ResultCheckBlock { + blocksRes := m.RetrieveBlocks(dataLayerHeight) + return da.ResultCheckBlock{DAResult: da.DAResult{Code: blocksRes.Code}, DataAvailable: len(blocksRes.Blocks) > 0} } -// RetrieveBlock returns block at given height from data availability layer. -func (m *MockDataAvailabilityLayerClient) RetrieveBlock(height uint64) da.ResultRetrieveBlock { - hash, err := m.dalcKV.Get(getKey(height)) - if err != nil { - return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} - } - blob, err := m.dalcKV.Get(hash) - if err != nil { - return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} +// RetrieveBlocks returns block at given height from data availability layer. +func (m *MockDataAvailabilityLayerClient) RetrieveBlocks(dataLayerHeight uint64) da.ResultRetrieveBlocks { + if dataLayerHeight >= atomic.LoadUint64(&m.daHeight) { + return da.ResultRetrieveBlocks{DAResult: da.DAResult{Code: da.StatusError, Message: "block not found"}} } - block := &types.Block{} - err = block.UnmarshalBinary(blob) - if err != nil { - return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} + iter := m.dalcKV.PrefixIterator(getPrefix(dataLayerHeight)) + defer iter.Discard() + + var blocks []*types.Block + for iter.Valid() { + hash := iter.Value() + + blob, err := m.dalcKV.Get(hash) + if err != nil { + return da.ResultRetrieveBlocks{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} + } + + block := &types.Block{} + err = block.UnmarshalBinary(blob) + if err != nil { + return da.ResultRetrieveBlocks{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}} + } + blocks = append(blocks, block) + + iter.Next() } - return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, Block: block} + return da.ResultRetrieveBlocks{DAResult: da.DAResult{Code: da.StatusSuccess}, Blocks: blocks} } -func getKey(height uint64) []byte { +func getPrefix(daHeight uint64) []byte { b := make([]byte, 8) - binary.BigEndian.PutUint64(b, height) + binary.BigEndian.PutUint64(b, daHeight) return b } + +func getKey(daHeight uint64, height uint64) []byte { + b := make([]byte, 16) + binary.BigEndian.PutUint64(b, daHeight) + binary.BigEndian.PutUint64(b[8:], height) + return b +} + +func (m *MockDataAvailabilityLayerClient) updateDAHeight() { + blockStep := rand.Uint64()%10 + 1 + atomic.AddUint64(&m.daHeight, blockStep) +} diff --git a/da/test/da_test.go b/da/test/da_test.go index 70a92a800..460ab41e4 100644 --- a/da/test/da_test.go +++ b/da/test/da_test.go @@ -5,21 +5,24 @@ import ( "net" "strconv" "testing" - - grpcda "github.com/celestiaorg/optimint/da/grpc" - "github.com/celestiaorg/optimint/da/grpc/mockserv" - "github.com/celestiaorg/optimint/store" - "google.golang.org/grpc" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/grpc" "github.com/celestiaorg/optimint/da" + grpcda "github.com/celestiaorg/optimint/da/grpc" + "github.com/celestiaorg/optimint/da/grpc/mockserv" + "github.com/celestiaorg/optimint/da/mock" "github.com/celestiaorg/optimint/da/registry" "github.com/celestiaorg/optimint/log/test" + "github.com/celestiaorg/optimint/store" "github.com/celestiaorg/optimint/types" ) +const mockDaBlockTime = 100 * time.Millisecond + func TestLifecycle(t *testing.T) { srv := startMockServ(t) defer srv.GracefulStop() @@ -33,7 +36,7 @@ func TestLifecycle(t *testing.T) { func doTestLifecycle(t *testing.T, dalc da.DataAvailabilityLayerClient) { require := require.New(t) - err := dalc.Init([]byte{}, nil, &test.TestLogger{T: t}) + err := dalc.Init([]byte{}, nil, test.NewTestLogger(t)) require.NoError(err) err = dalc.Start() @@ -57,33 +60,45 @@ func doTestDALC(t *testing.T, dalc da.DataAvailabilityLayerClient) { require := require.New(t) assert := assert.New(t) - err := dalc.Init([]byte{}, store.NewDefaultInMemoryKVStore(), &test.TestLogger{T: t}) + // mock DALC will advance block height every 100ms + conf := []byte{} + if _, ok := dalc.(*mock.MockDataAvailabilityLayerClient); ok { + conf = []byte(mockDaBlockTime.String()) + } + err := dalc.Init(conf, store.NewDefaultInMemoryKVStore(), test.NewTestLogger(t)) require.NoError(err) err = dalc.Start() require.NoError(err) + // wait a bit more than mockDaBlockTime, so mock can "produce" some blocks + time.Sleep(mockDaBlockTime + 20*time.Millisecond) + // only blocks b1 and b2 will be submitted to DA b1 := getRandomBlock(1, 10) b2 := getRandomBlock(2, 10) - b3 := getRandomBlock(1, 10) resp := dalc.SubmitBlock(b1) + h1 := resp.DAHeight assert.Equal(da.StatusSuccess, resp.Code) resp = dalc.SubmitBlock(b2) + h2 := resp.DAHeight assert.Equal(da.StatusSuccess, resp.Code) - check := dalc.CheckBlockAvailability(&b1.Header) + // wait a bit more than mockDaBlockTime, so optimint blocks can be "included" in mock block + time.Sleep(mockDaBlockTime + 20*time.Millisecond) + + check := dalc.CheckBlockAvailability(h1) assert.Equal(da.StatusSuccess, check.Code) assert.True(check.DataAvailable) - check = dalc.CheckBlockAvailability(&b2.Header) + check = dalc.CheckBlockAvailability(h2) assert.Equal(da.StatusSuccess, check.Code) assert.True(check.DataAvailable) - // this block was never submitted to DA - check = dalc.CheckBlockAvailability(&b3.Header) + // this height should not be used by DALC + check = dalc.CheckBlockAvailability(h1 - 1) assert.Equal(da.StatusSuccess, check.Code) assert.False(check.DataAvailable) } @@ -104,7 +119,7 @@ func TestRetrieve(t *testing.T) { func startMockServ(t *testing.T) *grpc.Server { conf := grpcda.DefaultConfig - srv := mockserv.GetServer(store.NewDefaultInMemoryKVStore(), conf) + srv := mockserv.GetServer(store.NewDefaultInMemoryKVStore(), conf, []byte(mockDaBlockTime.String())) lis, err := net.Listen("tcp", conf.Host+":"+strconv.Itoa(conf.Port)) if err != nil { t.Fatal(err) @@ -119,22 +134,49 @@ func doTestRetrieve(t *testing.T, dalc da.DataAvailabilityLayerClient) { require := require.New(t) assert := assert.New(t) - err := dalc.Init([]byte{}, store.NewDefaultInMemoryKVStore(), &test.TestLogger{T: t}) + // mock DALC will advance block height every 100ms + conf := []byte{} + if _, ok := dalc.(*mock.MockDataAvailabilityLayerClient); ok { + conf = []byte(mockDaBlockTime.String()) + } + err := dalc.Init(conf, store.NewDefaultInMemoryKVStore(), test.NewTestLogger(t)) require.NoError(err) err = dalc.Start() require.NoError(err) + // wait a bit more than mockDaBlockTime, so mock can "produce" some blocks + time.Sleep(mockDaBlockTime + 20*time.Millisecond) + retriever := dalc.(da.BlockRetriever) + countAtHeight := make(map[uint64]int) + blocks := make(map[*types.Block]uint64) for i := uint64(0); i < 100; i++ { b := getRandomBlock(i, rand.Int()%20) resp := dalc.SubmitBlock(b) assert.Equal(da.StatusSuccess, resp.Code) + time.Sleep(time.Duration(rand.Int63() % mockDaBlockTime.Milliseconds())) + + countAtHeight[resp.DAHeight]++ + blocks[b] = resp.DAHeight + } + + // wait a bit more than mockDaBlockTime, so mock can "produce" last blocks + time.Sleep(mockDaBlockTime + 20*time.Millisecond) + + for h, cnt := range countAtHeight { + ret := retriever.RetrieveBlocks(h) + assert.Equal(da.StatusSuccess, ret.Code) + require.NotEmpty(ret.Blocks) + assert.Len(ret.Blocks, cnt) + } - ret := retriever.RetrieveBlock(i) + for b, h := range blocks { + ret := retriever.RetrieveBlocks(h) assert.Equal(da.StatusSuccess, ret.Code) - assert.Equal(b, ret.Block) + require.NotEmpty(ret.Blocks) + assert.Contains(ret.Blocks, b) } } diff --git a/docs/lazy-adr/adr-001-node-interface.md b/docs/lazy-adr/adr-001-node-interface.md index 8474e58d5..8ba5a0901 100644 --- a/docs/lazy-adr/adr-001-node-interface.md +++ b/docs/lazy-adr/adr-001-node-interface.md @@ -3,35 +3,41 @@ Replacing on the `Node` level gives much flexibility. Still, significant amount of code can be reused, and there is no need to refactor lazyledger-core. Cosmos SDK is tigtly coupled with Tendermint with regards to node creation, RPC, app initialization, etc. De-coupling requires big refactoring of cosmos-sdk. -There are known issues related to Tendermint RPC communication. +There are known issues related to Tendermint RPC communication. ## Replacing Tendermint `Node` + Tendermint `Node` is a struct. It's used directly in cosmos-sdk (not via interface). We don't need to introduce common interface `Node`s, because the plan is to use scafolding tool in the feature, so we can make any required changes in cosmos-sdk. -### Interface required by cosmos-sdk: + +### Interface required by cosmos-sdk + * BaseService (struct): * Service (interface) - * Start() - * IsRunning() - * Stop() + * Start() + * IsRunning() + * Stop() * Logger * Direct access: * ConfigureRPC() * EventBus() ## Alternative approaches + ### Create RPC from scratch + * Pros: * May be possible to avoid Tendermint issues * Should be possible to avoid dependency on Tendermint in Optimint - * Changes probably limited to cosmos-sdk (not required in tendermint/lazyledger-core) + * Changes probably limited to cosmos-sdk (not required in tendermint/lazyledger-core) * Cons: * Reinventing the wheel * Requires bigger, much more complicated changes in cosmos-sdk * Probably can't upstream such changes to cosmos-sdk ## `tendermint` vs `lazyledger-core` -Right now, either `tendermint` or `lazyledger-core` can be used for base types (including interfaces). + +Right now, either `tendermint` or `lazyledger-core` can be used for base types (including interfaces). Similarly, vanilla `cosomos-sdk` (not a fork under lazyledger organization) can be used as a base for ORU client. `lazyledger-core` is a repository created because of needs related to lazyledger client, not optimistic rollups client. On the other hand, some of the functionality will be shared between both clients. This will have to be resolved later in time. @@ -39,5 +45,5 @@ Using 'vanilla' repositories (not forks) probably will make easier to upstream c easier. ## Development -For development, there is `master-optimint` branch in `cosmos-sdk` repository. Versions with `-optimint` suffix will be released from this branch for easier dependency management during development. +For development, there is `master-optimint` branch in `cosmos-sdk` repository. Versions with `-optimint` suffix will be released from this branch for easier dependency management during development. diff --git a/docs/lazy-adr/adr-002-mempool.md b/docs/lazy-adr/adr-002-mempool.md index a9844f7c8..a0c141419 100644 --- a/docs/lazy-adr/adr-002-mempool.md +++ b/docs/lazy-adr/adr-002-mempool.md @@ -3,6 +3,7 @@ For now, mempool implementation from lazyledger-core/Tendermint will be used. ## Pros + * good integration with other re-used code (see ADR-001) * well tested * glue code is not required @@ -11,12 +12,14 @@ For now, mempool implementation from lazyledger-core/Tendermint will be used. * mempool does not require any knowledge about the internal structure of the Txs and is already "abci-ready" ## Cons + * inherit all limitations of the tendermint mempool * no prioritization of Txs * many [open issues](https://github.com/tendermint/tendermint/issues?q=is%3Aissue+is%3Aopen+mempool+label%3AC%3Amempool) * legacy code base (the tendermint mempool exists for a while now) ## Alternatives + * Implementation from scratch * time consuming * error prone diff --git a/docs/lazy-adr/adr-003-peer-discovery.md b/docs/lazy-adr/adr-003-peer-discovery.md index 123c50977..92d723251 100644 --- a/docs/lazy-adr/adr-003-peer-discovery.md +++ b/docs/lazy-adr/adr-003-peer-discovery.md @@ -3,6 +3,7 @@ Libp2p provides multiple ways to discover peers (DHT, mDNS, PubSub peer exchange). Currently there are no plans to support mDNS (as it's limited to local networks). ## Proposed network architecture + 1. There will be a set of well-known, application-agnostic seed nodes. Every optimint client will be able to connect to such node, addresses will be saved in configuration. * This does not limit applications as they can still create independent networks with separate set of seed nodes. 2. Nodes in the network will serve DHT. It will be used for active peer discovery. Client of each ORU network will be able to find other peers in this particular network. @@ -12,13 +13,16 @@ Libp2p provides multiple ways to discover peers (DHT, mDNS, PubSub peer exchange 4. After connecting to nodes found in DHT, GossipSub will handle peer lists for clients. ### Pros + * Shared DHT should make it easier to find peers. * Use of existing libraries. ### Cons + * There may be some overhead for clients to handle DHT requests from other ORU networks. ## Alternatives + 1. Joining public IPFS DHT for peer discovery. * pros: large network - finding peers should be very easy * cons: we may affect public IPFS network stability in case of misconfiguration, possibly lot of unrelated traffic diff --git a/docs/lazy-adr/adr-004-core-types.md b/docs/lazy-adr/adr-004-core-types.md index c5be75edb..3329437e6 100644 --- a/docs/lazy-adr/adr-004-core-types.md +++ b/docs/lazy-adr/adr-004-core-types.md @@ -11,14 +11,15 @@ This document describes the core data structures of any Optimint-powered blockch ## Alternative Approaches Alternatives for ChainID: - - an integer type like unit64 - - a string that fulfills some basic rules like the ChainID for Cosmos chains + +- an integer type like unit64 +- a string that fulfills some basic rules like the ChainID for Cosmos chains ## Decision -We design the core data types as minimalistic as possible, i.e. they only contain the absolute necessary -data for an optimistic rollup to function properly. -If there are any additional fields that conflict with above's claimed minimalism, then they are necessarily inherited +We design the core data types as minimalistic as possible, i.e. they only contain the absolute necessary +data for an optimistic rollup to function properly. +If there are any additional fields that conflict with above's claimed minimalism, then they are necessarily inherited by the ABCI imposed separation between application state machine and consensus/networking (often also referred to as ABCI-server and -client). Where such tradeoffs are made, we explicitly comment on them. @@ -104,11 +105,11 @@ type EvidenceData struct { The details for this will be defined in a separated adr/PR. Here is an incomplete list of potenial evidence types: + - Same Aggregator signed two different blocks at the same height - figure out if this is actually malicious / slashable behaviour - e.g. clients could simply accept the last block included in a LL block - State Transition Fraud Proofs (for previous blocks) - #### Commit ```go @@ -122,15 +123,14 @@ type Commit struct { #### ConsensusParams [ConsensusParams](https://docs.tendermint.com/master/spec/core/state.html#consensusparams) can be updated by the application through ABCI. -This could be seen as a state transition and the ConsensusHash in the header would then require a dedicated state fraud proof. +This could be seen as a state transition and the ConsensusHash in the header would then require a dedicated state fraud proof. That said, none of the existing default Cosmos-SDK modules actually make use of this functionality though. -Hence, we can treat the ConsensusParams as constants (for the same app version). -We clearly need to communicate this to optimistic rollup chain developers. +Hence, we can treat the ConsensusParams as constants (for the same app version). +We clearly need to communicate this to optimistic rollup chain developers. Ideally, we should ensure this programmatically to guarantee that this assumption always holds inside optimint. The ConsensusParams have the exact same structure as in Tendermint. For the sake of self-containedness we still list them here: - ```go // ConsensusParams contains consensus critical parameters that determine the // validity of blocks. @@ -196,7 +196,6 @@ For finishing the implementation these items need to be tackled at least: - [ ] equivalent types for serialization purposes (probably protobuf) - [ ] conversion from and to protobuf - ## Consequences ### Positive @@ -211,6 +210,4 @@ For finishing the implementation these items need to be tackled at least: ## References -- https://github.com/celestiaorg/optimint/pull/41 - - +- diff --git a/docs/lazy-adr/adr-005-serialization.md b/docs/lazy-adr/adr-005-serialization.md index 08f57c28a..2e94a80b6 100644 --- a/docs/lazy-adr/adr-005-serialization.md +++ b/docs/lazy-adr/adr-005-serialization.md @@ -14,7 +14,7 @@ There are countless alternatives to `protobuf`, including `flatbuffers`, `avro`, ## Decision -`protobuf` is used for data serialization both for storing and network communication. +`protobuf` is used for data serialization both for storing and network communication. `protobuf` is used widely in entire Cosmos ecosystem, and we would need to use it anyways. ## Status @@ -24,12 +24,14 @@ There are countless alternatives to `protobuf`, including `flatbuffers`, `avro`, ## Consequences ### Positive - * well known serialization method - * language independent + +- well known serialization method +- language independent ### Negative - * there are known issues with `protobuf` + +- there are known issues with `protobuf` ### Neutral - * it's de-facto standard in Cosmos ecosystem +- it's de-facto standard in Cosmos ecosystem diff --git a/docs/lazy-adr/adr-006-da-interface.md b/docs/lazy-adr/adr-006-da-interface.md index c97e5ee32..c0cf7564d 100644 --- a/docs/lazy-adr/adr-006-da-interface.md +++ b/docs/lazy-adr/adr-006-da-interface.md @@ -24,6 +24,7 @@ All the details are implementation-specific. ## Detailed Design Definition of interface: + ```go type DataAvailabilityLayerClient interface { // Init is called once to allow DA client to read configuration and initialize resources. @@ -109,4 +110,3 @@ Implemented ## References > Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here! - diff --git a/log/test/loggers.go b/log/test/loggers.go index 462fbd4a7..4eb305c90 100644 --- a/log/test/loggers.go +++ b/log/test/loggers.go @@ -8,10 +8,17 @@ import ( // TODO(tzdybal): move to some common place type TestLogger struct { - mtx sync.Mutex + mtx *sync.Mutex T *testing.T } +func NewTestLogger(t *testing.T) *TestLogger { + return &TestLogger{ + mtx: new(sync.Mutex), + T: t, + } +} + func (t *TestLogger) Debug(msg string, keyvals ...interface{}) { t.T.Helper() t.mtx.Lock() diff --git a/node/integration_test.go b/node/integration_test.go index 958dde9c1..568f548dd 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -103,7 +103,7 @@ func TestTxGossipingAndAggregation(t *testing.T) { require.NoError(nodes[i].P2P.GossipTx(context.TODO(), []byte(data))) } - timeout := time.NewTimer(time.Second * 5) + timeout := time.NewTimer(time.Second * 30) doneChan := make(chan struct{}) go func() { defer close(doneChan) diff --git a/p2p/client_test.go b/p2p/client_test.go index 437c30d96..49f9ee9a9 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -20,7 +20,7 @@ import ( func TestClientStartup(t *testing.T) { privKey, _, _ := crypto.GenerateEd25519Key(rand.Reader) - client, err := NewClient(config.P2PConfig{}, privKey, "TestChain", &test.TestLogger{T: t}) + client, err := NewClient(config.P2PConfig{}, privKey, "TestChain", test.NewTestLogger(t)) assert := assert.New(t) assert.NoError(err) assert.NotNil(client) @@ -35,7 +35,7 @@ func TestBootstrapping(t *testing.T) { //log.SetDebugLogging() assert := assert.New(t) - logger := &test.TestLogger{T: t} + logger := test.NewTestLogger(t) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -55,7 +55,7 @@ func TestBootstrapping(t *testing.T) { func TestDiscovery(t *testing.T) { assert := assert.New(t) - logger := &test.TestLogger{T: t} + logger := test.NewTestLogger(t) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -75,7 +75,7 @@ func TestDiscovery(t *testing.T) { func TestGossiping(t *testing.T) { assert := assert.New(t) - logger := &test.TestLogger{T: t} + logger := test.NewTestLogger(t) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/proto/dalc/dalc.proto b/proto/dalc/dalc.proto index 56d5477d0..cbe3f6e89 100644 --- a/proto/dalc/dalc.proto +++ b/proto/dalc/dalc.proto @@ -14,6 +14,7 @@ enum StatusCode { message DAResponse { StatusCode code = 1; string message = 2; + uint64 data_layer_height = 3; } message SubmitBlockRequest { @@ -25,7 +26,7 @@ message SubmitBlockResponse { } message CheckBlockAvailabilityRequest { - optimint.Header header = 1; + uint64 data_layer_height = 1; } message CheckBlockAvailabilityResponse { @@ -33,17 +34,17 @@ message CheckBlockAvailabilityResponse { bool data_available = 2; } -message RetrieveBlockRequest { - uint64 height = 1; +message RetrieveBlocksRequest { + uint64 data_layer_height = 1; } -message RetrieveBlockResponse { +message RetrieveBlocksResponse { DAResponse result = 1; - optimint.Block block = 2; + repeated optimint.Block blocks = 2; } service DALCService { rpc SubmitBlock(SubmitBlockRequest) returns (SubmitBlockResponse) {} rpc CheckBlockAvailability(CheckBlockAvailabilityRequest) returns (CheckBlockAvailabilityResponse) {} - rpc RetrieveBlock(RetrieveBlockRequest) returns (RetrieveBlockResponse) {} + rpc RetrieveBlocks(RetrieveBlocksRequest) returns (RetrieveBlocksResponse) {} } diff --git a/state/state.go b/state/state.go index c1c98b757..a04ce28fc 100644 --- a/state/state.go +++ b/state/state.go @@ -37,6 +37,8 @@ type State struct { LastBlockID types.BlockID LastBlockTime time.Time + DAHeight uint64 + // In the MVP implementation, there will be only one Validator NextValidators *types.ValidatorSet Validators *types.ValidatorSet @@ -80,6 +82,8 @@ func NewFromGenesisDoc(genDoc *types.GenesisDoc) (State, error) { ChainID: genDoc.ChainID, InitialHeight: genDoc.InitialHeight, + DAHeight: 1, + LastBlockHeight: 0, LastBlockID: types.BlockID{}, LastBlockTime: genDoc.GenesisTime, diff --git a/store/store.go b/store/store.go index a8ac1968c..6803a882f 100644 --- a/store/store.go +++ b/store/store.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "fmt" - "sync" + "sync/atomic" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -30,9 +30,6 @@ type DefaultStore struct { db KVStore height uint64 - - // mtx ensures that db is in sync with height - mtx sync.RWMutex } var _ Store = &DefaultStore{} @@ -46,9 +43,7 @@ func New(kv KVStore) Store { // Height returns height of the highest block saved in the Store. func (s *DefaultStore) Height() uint64 { - s.mtx.RLock() - defer s.mtx.RUnlock() - return s.height + return atomic.LoadUint64(&s.height) } // SaveBlock adds block to the store along with corresponding commit. @@ -65,9 +60,6 @@ func (s *DefaultStore) SaveBlock(block *types.Block, commit *types.Commit) error return err } - s.mtx.Lock() - defer s.mtx.Unlock() - bb := s.db.NewBatch() err = multierr.Append(err, bb.Set(getBlockKey(hash), blockBlob)) err = multierr.Append(err, bb.Set(getCommitKey(hash), commitBlob)) @@ -82,8 +74,8 @@ func (s *DefaultStore) SaveBlock(block *types.Block, commit *types.Commit) error return err } - if block.Header.Height > s.height { - s.height = block.Header.Height + if block.Header.Height > atomic.LoadUint64(&s.height) { + atomic.StoreUint64(&s.height, block.Header.Height) } return nil @@ -176,9 +168,7 @@ func (s *DefaultStore) LoadState() (state.State, error) { } err = json.Unmarshal(blob, &state) - s.mtx.Lock() - s.height = uint64(state.LastBlockHeight) - s.mtx.Unlock() + atomic.StoreUint64(&s.height, uint64(state.LastBlockHeight)) return state, err } diff --git a/types/pb/dalc/dalc.pb.go b/types/pb/dalc/dalc.pb.go index 809eab681..ffcad377c 100644 --- a/types/pb/dalc/dalc.pb.go +++ b/types/pb/dalc/dalc.pb.go @@ -13,22 +13,26 @@ SubmitBlockResponse CheckBlockAvailabilityRequest CheckBlockAvailabilityResponse - RetrieveBlockRequest - RetrieveBlockResponse + RetrieveBlocksRequest + RetrieveBlocksResponse */ package dalc -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import optimint "github.com/celestiaorg/optimint/types/pb/optimint" - import ( + fmt "fmt" + + proto "github.com/golang/protobuf/proto" + + math "math" + + optimint "github.com/celestiaorg/optimint/types/pb/optimint" + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" -) -import io "io" + io "io" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -69,8 +73,9 @@ func (x StatusCode) String() string { func (StatusCode) EnumDescriptor() ([]byte, []int) { return fileDescriptorDalc, []int{0} } type DAResponse struct { - Code StatusCode `protobuf:"varint,1,opt,name=code,proto3,enum=dalc.StatusCode" json:"code,omitempty"` - Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + Code StatusCode `protobuf:"varint,1,opt,name=code,proto3,enum=dalc.StatusCode" json:"code,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + DataLayerHeight uint64 `protobuf:"varint,3,opt,name=data_layer_height,json=dataLayerHeight,proto3" json:"data_layer_height,omitempty"` } func (m *DAResponse) Reset() { *m = DAResponse{} } @@ -92,6 +97,13 @@ func (m *DAResponse) GetMessage() string { return "" } +func (m *DAResponse) GetDataLayerHeight() uint64 { + if m != nil { + return m.DataLayerHeight + } + return 0 +} + type SubmitBlockRequest struct { Block *optimint.Block `protobuf:"bytes,1,opt,name=block" json:"block,omitempty"` } @@ -125,7 +137,7 @@ func (m *SubmitBlockResponse) GetResult() *DAResponse { } type CheckBlockAvailabilityRequest struct { - Header *optimint.Header `protobuf:"bytes,1,opt,name=header" json:"header,omitempty"` + DataLayerHeight uint64 `protobuf:"varint,1,opt,name=data_layer_height,json=dataLayerHeight,proto3" json:"data_layer_height,omitempty"` } func (m *CheckBlockAvailabilityRequest) Reset() { *m = CheckBlockAvailabilityRequest{} } @@ -135,11 +147,11 @@ func (*CheckBlockAvailabilityRequest) Descriptor() ([]byte, []int) { return fileDescriptorDalc, []int{3} } -func (m *CheckBlockAvailabilityRequest) GetHeader() *optimint.Header { +func (m *CheckBlockAvailabilityRequest) GetDataLayerHeight() uint64 { if m != nil { - return m.Header + return m.DataLayerHeight } - return nil + return 0 } type CheckBlockAvailabilityResponse struct { @@ -168,42 +180,42 @@ func (m *CheckBlockAvailabilityResponse) GetDataAvailable() bool { return false } -type RetrieveBlockRequest struct { - Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` +type RetrieveBlocksRequest struct { + DataLayerHeight uint64 `protobuf:"varint,1,opt,name=data_layer_height,json=dataLayerHeight,proto3" json:"data_layer_height,omitempty"` } -func (m *RetrieveBlockRequest) Reset() { *m = RetrieveBlockRequest{} } -func (m *RetrieveBlockRequest) String() string { return proto.CompactTextString(m) } -func (*RetrieveBlockRequest) ProtoMessage() {} -func (*RetrieveBlockRequest) Descriptor() ([]byte, []int) { return fileDescriptorDalc, []int{5} } +func (m *RetrieveBlocksRequest) Reset() { *m = RetrieveBlocksRequest{} } +func (m *RetrieveBlocksRequest) String() string { return proto.CompactTextString(m) } +func (*RetrieveBlocksRequest) ProtoMessage() {} +func (*RetrieveBlocksRequest) Descriptor() ([]byte, []int) { return fileDescriptorDalc, []int{5} } -func (m *RetrieveBlockRequest) GetHeight() uint64 { +func (m *RetrieveBlocksRequest) GetDataLayerHeight() uint64 { if m != nil { - return m.Height + return m.DataLayerHeight } return 0 } -type RetrieveBlockResponse struct { - Result *DAResponse `protobuf:"bytes,1,opt,name=result" json:"result,omitempty"` - Block *optimint.Block `protobuf:"bytes,2,opt,name=block" json:"block,omitempty"` +type RetrieveBlocksResponse struct { + Result *DAResponse `protobuf:"bytes,1,opt,name=result" json:"result,omitempty"` + Blocks []*optimint.Block `protobuf:"bytes,2,rep,name=blocks" json:"blocks,omitempty"` } -func (m *RetrieveBlockResponse) Reset() { *m = RetrieveBlockResponse{} } -func (m *RetrieveBlockResponse) String() string { return proto.CompactTextString(m) } -func (*RetrieveBlockResponse) ProtoMessage() {} -func (*RetrieveBlockResponse) Descriptor() ([]byte, []int) { return fileDescriptorDalc, []int{6} } +func (m *RetrieveBlocksResponse) Reset() { *m = RetrieveBlocksResponse{} } +func (m *RetrieveBlocksResponse) String() string { return proto.CompactTextString(m) } +func (*RetrieveBlocksResponse) ProtoMessage() {} +func (*RetrieveBlocksResponse) Descriptor() ([]byte, []int) { return fileDescriptorDalc, []int{6} } -func (m *RetrieveBlockResponse) GetResult() *DAResponse { +func (m *RetrieveBlocksResponse) GetResult() *DAResponse { if m != nil { return m.Result } return nil } -func (m *RetrieveBlockResponse) GetBlock() *optimint.Block { +func (m *RetrieveBlocksResponse) GetBlocks() []*optimint.Block { if m != nil { - return m.Block + return m.Blocks } return nil } @@ -214,8 +226,8 @@ func init() { proto.RegisterType((*SubmitBlockResponse)(nil), "dalc.SubmitBlockResponse") proto.RegisterType((*CheckBlockAvailabilityRequest)(nil), "dalc.CheckBlockAvailabilityRequest") proto.RegisterType((*CheckBlockAvailabilityResponse)(nil), "dalc.CheckBlockAvailabilityResponse") - proto.RegisterType((*RetrieveBlockRequest)(nil), "dalc.RetrieveBlockRequest") - proto.RegisterType((*RetrieveBlockResponse)(nil), "dalc.RetrieveBlockResponse") + proto.RegisterType((*RetrieveBlocksRequest)(nil), "dalc.RetrieveBlocksRequest") + proto.RegisterType((*RetrieveBlocksResponse)(nil), "dalc.RetrieveBlocksResponse") proto.RegisterEnum("dalc.StatusCode", StatusCode_name, StatusCode_value) } @@ -232,7 +244,7 @@ const _ = grpc.SupportPackageIsVersion4 type DALCServiceClient interface { SubmitBlock(ctx context.Context, in *SubmitBlockRequest, opts ...grpc.CallOption) (*SubmitBlockResponse, error) CheckBlockAvailability(ctx context.Context, in *CheckBlockAvailabilityRequest, opts ...grpc.CallOption) (*CheckBlockAvailabilityResponse, error) - RetrieveBlock(ctx context.Context, in *RetrieveBlockRequest, opts ...grpc.CallOption) (*RetrieveBlockResponse, error) + RetrieveBlocks(ctx context.Context, in *RetrieveBlocksRequest, opts ...grpc.CallOption) (*RetrieveBlocksResponse, error) } type dALCServiceClient struct { @@ -261,9 +273,9 @@ func (c *dALCServiceClient) CheckBlockAvailability(ctx context.Context, in *Chec return out, nil } -func (c *dALCServiceClient) RetrieveBlock(ctx context.Context, in *RetrieveBlockRequest, opts ...grpc.CallOption) (*RetrieveBlockResponse, error) { - out := new(RetrieveBlockResponse) - err := grpc.Invoke(ctx, "/dalc.DALCService/RetrieveBlock", in, out, c.cc, opts...) +func (c *dALCServiceClient) RetrieveBlocks(ctx context.Context, in *RetrieveBlocksRequest, opts ...grpc.CallOption) (*RetrieveBlocksResponse, error) { + out := new(RetrieveBlocksResponse) + err := grpc.Invoke(ctx, "/dalc.DALCService/RetrieveBlocks", in, out, c.cc, opts...) if err != nil { return nil, err } @@ -275,7 +287,7 @@ func (c *dALCServiceClient) RetrieveBlock(ctx context.Context, in *RetrieveBlock type DALCServiceServer interface { SubmitBlock(context.Context, *SubmitBlockRequest) (*SubmitBlockResponse, error) CheckBlockAvailability(context.Context, *CheckBlockAvailabilityRequest) (*CheckBlockAvailabilityResponse, error) - RetrieveBlock(context.Context, *RetrieveBlockRequest) (*RetrieveBlockResponse, error) + RetrieveBlocks(context.Context, *RetrieveBlocksRequest) (*RetrieveBlocksResponse, error) } func RegisterDALCServiceServer(s *grpc.Server, srv DALCServiceServer) { @@ -318,20 +330,20 @@ func _DALCService_CheckBlockAvailability_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } -func _DALCService_RetrieveBlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(RetrieveBlockRequest) +func _DALCService_RetrieveBlocks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RetrieveBlocksRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(DALCServiceServer).RetrieveBlock(ctx, in) + return srv.(DALCServiceServer).RetrieveBlocks(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/dalc.DALCService/RetrieveBlock", + FullMethod: "/dalc.DALCService/RetrieveBlocks", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DALCServiceServer).RetrieveBlock(ctx, req.(*RetrieveBlockRequest)) + return srv.(DALCServiceServer).RetrieveBlocks(ctx, req.(*RetrieveBlocksRequest)) } return interceptor(ctx, in, info, handler) } @@ -349,8 +361,8 @@ var _DALCService_serviceDesc = grpc.ServiceDesc{ Handler: _DALCService_CheckBlockAvailability_Handler, }, { - MethodName: "RetrieveBlock", - Handler: _DALCService_RetrieveBlock_Handler, + MethodName: "RetrieveBlocks", + Handler: _DALCService_RetrieveBlocks_Handler, }, }, Streams: []grpc.StreamDesc{}, @@ -383,6 +395,11 @@ func (m *DAResponse) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintDalc(dAtA, i, uint64(len(m.Message))) i += copy(dAtA[i:], m.Message) } + if m.DataLayerHeight != 0 { + dAtA[i] = 0x18 + i++ + i = encodeVarintDalc(dAtA, i, uint64(m.DataLayerHeight)) + } return i, nil } @@ -457,15 +474,10 @@ func (m *CheckBlockAvailabilityRequest) MarshalTo(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Header != nil { - dAtA[i] = 0xa + if m.DataLayerHeight != 0 { + dAtA[i] = 0x8 i++ - i = encodeVarintDalc(dAtA, i, uint64(m.Header.Size())) - n3, err := m.Header.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n3 + i = encodeVarintDalc(dAtA, i, uint64(m.DataLayerHeight)) } return i, nil } @@ -489,11 +501,11 @@ func (m *CheckBlockAvailabilityResponse) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintDalc(dAtA, i, uint64(m.Result.Size())) - n4, err := m.Result.MarshalTo(dAtA[i:]) + n3, err := m.Result.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n4 + i += n3 } if m.DataAvailable { dAtA[i] = 0x10 @@ -508,7 +520,7 @@ func (m *CheckBlockAvailabilityResponse) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *RetrieveBlockRequest) Marshal() (dAtA []byte, err error) { +func (m *RetrieveBlocksRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -518,20 +530,20 @@ func (m *RetrieveBlockRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RetrieveBlockRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *RetrieveBlocksRequest) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l - if m.Height != 0 { + if m.DataLayerHeight != 0 { dAtA[i] = 0x8 i++ - i = encodeVarintDalc(dAtA, i, uint64(m.Height)) + i = encodeVarintDalc(dAtA, i, uint64(m.DataLayerHeight)) } return i, nil } -func (m *RetrieveBlockResponse) Marshal() (dAtA []byte, err error) { +func (m *RetrieveBlocksResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -541,7 +553,7 @@ func (m *RetrieveBlockResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RetrieveBlockResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *RetrieveBlocksResponse) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int @@ -550,21 +562,23 @@ func (m *RetrieveBlockResponse) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintDalc(dAtA, i, uint64(m.Result.Size())) - n5, err := m.Result.MarshalTo(dAtA[i:]) + n4, err := m.Result.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n5 + i += n4 } - if m.Block != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintDalc(dAtA, i, uint64(m.Block.Size())) - n6, err := m.Block.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if len(m.Blocks) > 0 { + for _, msg := range m.Blocks { + dAtA[i] = 0x12 + i++ + i = encodeVarintDalc(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } - i += n6 } return i, nil } @@ -606,6 +620,9 @@ func (m *DAResponse) Size() (n int) { if l > 0 { n += 1 + l + sovDalc(uint64(l)) } + if m.DataLayerHeight != 0 { + n += 1 + sovDalc(uint64(m.DataLayerHeight)) + } return n } @@ -632,9 +649,8 @@ func (m *SubmitBlockResponse) Size() (n int) { func (m *CheckBlockAvailabilityRequest) Size() (n int) { var l int _ = l - if m.Header != nil { - l = m.Header.Size() - n += 1 + l + sovDalc(uint64(l)) + if m.DataLayerHeight != 0 { + n += 1 + sovDalc(uint64(m.DataLayerHeight)) } return n } @@ -652,25 +668,27 @@ func (m *CheckBlockAvailabilityResponse) Size() (n int) { return n } -func (m *RetrieveBlockRequest) Size() (n int) { +func (m *RetrieveBlocksRequest) Size() (n int) { var l int _ = l - if m.Height != 0 { - n += 1 + sovDalc(uint64(m.Height)) + if m.DataLayerHeight != 0 { + n += 1 + sovDalc(uint64(m.DataLayerHeight)) } return n } -func (m *RetrieveBlockResponse) Size() (n int) { +func (m *RetrieveBlocksResponse) Size() (n int) { var l int _ = l if m.Result != nil { l = m.Result.Size() n += 1 + l + sovDalc(uint64(l)) } - if m.Block != nil { - l = m.Block.Size() - n += 1 + l + sovDalc(uint64(l)) + if len(m.Blocks) > 0 { + for _, e := range m.Blocks { + l = e.Size() + n += 1 + l + sovDalc(uint64(l)) + } } return n } @@ -765,6 +783,25 @@ func (m *DAResponse) Unmarshal(dAtA []byte) error { } m.Message = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DataLayerHeight", wireType) + } + m.DataLayerHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDalc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DataLayerHeight |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipDalc(dAtA[iNdEx:]) @@ -982,10 +1019,10 @@ func (m *CheckBlockAvailabilityRequest) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DataLayerHeight", wireType) } - var msglen int + m.DataLayerHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDalc @@ -995,25 +1032,11 @@ func (m *CheckBlockAvailabilityRequest) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + m.DataLayerHeight |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthDalc - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Header == nil { - m.Header = &optimint.Header{} - } - if err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipDalc(dAtA[iNdEx:]) @@ -1138,7 +1161,7 @@ func (m *CheckBlockAvailabilityResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *RetrieveBlockRequest) Unmarshal(dAtA []byte) error { +func (m *RetrieveBlocksRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1161,17 +1184,17 @@ func (m *RetrieveBlockRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: RetrieveBlockRequest: wiretype end group for non-group") + return fmt.Errorf("proto: RetrieveBlocksRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: RetrieveBlockRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: RetrieveBlocksRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DataLayerHeight", wireType) } - m.Height = 0 + m.DataLayerHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDalc @@ -1181,7 +1204,7 @@ func (m *RetrieveBlockRequest) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Height |= (uint64(b) & 0x7F) << shift + m.DataLayerHeight |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1207,7 +1230,7 @@ func (m *RetrieveBlockRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *RetrieveBlockResponse) Unmarshal(dAtA []byte) error { +func (m *RetrieveBlocksResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1230,10 +1253,10 @@ func (m *RetrieveBlockResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: RetrieveBlockResponse: wiretype end group for non-group") + return fmt.Errorf("proto: RetrieveBlocksResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: RetrieveBlockResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: RetrieveBlocksResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1271,7 +1294,7 @@ func (m *RetrieveBlockResponse) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Block", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1295,10 +1318,8 @@ func (m *RetrieveBlockResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Block == nil { - m.Block = &optimint.Block{} - } - if err := m.Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Blocks = append(m.Blocks, &optimint.Block{}) + if err := m.Blocks[len(m.Blocks)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1431,37 +1452,38 @@ var ( func init() { proto.RegisterFile("dalc/dalc.proto", fileDescriptorDalc) } var fileDescriptorDalc = []byte{ - // 501 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xae, 0x43, 0x08, 0x30, 0x51, 0xdb, 0xb0, 0xa5, 0x4d, 0x48, 0x45, 0x54, 0x99, 0x56, 0x8a, - 0x90, 0xb0, 0xa5, 0x70, 0xe4, 0x50, 0xb9, 0xb6, 0x11, 0x41, 0x85, 0xa0, 0x75, 0x72, 0xe1, 0x12, - 0xad, 0xed, 0x51, 0xbc, 0xaa, 0x53, 0xbb, 0xf6, 0x3a, 0x52, 0x5f, 0x80, 0x67, 0xe0, 0x91, 0x38, - 0xf2, 0x08, 0x28, 0xbc, 0x08, 0xf2, 0x6f, 0x93, 0x12, 0x22, 0xc1, 0xc5, 0xda, 0x99, 0x6f, 0xe6, - 0xdb, 0xcf, 0x3b, 0xdf, 0x2e, 0xec, 0xbb, 0xcc, 0x77, 0xd4, 0xf4, 0xa3, 0x84, 0x51, 0x20, 0x02, - 0x52, 0x4f, 0xd7, 0xdd, 0x76, 0x10, 0x0a, 0x3e, 0xe7, 0xd7, 0x42, 0x2d, 0x17, 0x39, 0x2c, 0x5f, - 0x02, 0x18, 0x1a, 0xc5, 0x38, 0x0c, 0xae, 0x63, 0x24, 0xa7, 0x50, 0x77, 0x02, 0x17, 0x3b, 0xd2, - 0x89, 0xd4, 0xdf, 0x1b, 0xb4, 0x94, 0x8c, 0xc7, 0x12, 0x4c, 0x24, 0xb1, 0x1e, 0xb8, 0x48, 0x33, - 0x94, 0x74, 0xe0, 0xd1, 0x1c, 0xe3, 0x98, 0xcd, 0xb0, 0x53, 0x3b, 0x91, 0xfa, 0x4f, 0x68, 0x19, - 0xca, 0x6f, 0x81, 0x58, 0x89, 0x3d, 0xe7, 0xe2, 0xc2, 0x0f, 0x9c, 0x2b, 0x8a, 0x37, 0x09, 0xc6, - 0x82, 0x9c, 0xc1, 0x43, 0x3b, 0x8d, 0x33, 0xda, 0xe6, 0x60, 0x5f, 0xa9, 0x34, 0xe4, 0x65, 0x39, - 0x2a, 0x9f, 0xc3, 0xc1, 0x5a, 0x73, 0xa1, 0xa9, 0x0f, 0x8d, 0x08, 0xe3, 0xc4, 0x17, 0x45, 0x7b, - 0xa1, 0xea, 0x4e, 0x35, 0x2d, 0x70, 0x79, 0x08, 0x2f, 0x74, 0x0f, 0x9d, 0xab, 0xac, 0x5f, 0x5b, - 0x30, 0xee, 0x33, 0x9b, 0xfb, 0x5c, 0xdc, 0x96, 0x42, 0xfa, 0xd0, 0xf0, 0x90, 0xb9, 0x18, 0x55, - 0x54, 0x95, 0x92, 0xf7, 0x59, 0x9e, 0x16, 0xb8, 0x7c, 0x03, 0xbd, 0xbf, 0x51, 0xfd, 0xab, 0x2c, - 0x72, 0x06, 0x7b, 0x2e, 0x13, 0x6c, 0xca, 0x72, 0x1a, 0x3f, 0x3f, 0xb5, 0xc7, 0x74, 0x37, 0xcd, - 0x6a, 0x65, 0x52, 0x56, 0xe0, 0x19, 0x45, 0x11, 0x71, 0x5c, 0xe0, 0xda, 0xe9, 0x1d, 0xa5, 0xa2, - 0xf9, 0xcc, 0xcb, 0x37, 0xaa, 0xd3, 0x22, 0x92, 0x3d, 0x38, 0xbc, 0x57, 0xff, 0x1f, 0xca, 0x8a, - 0xc1, 0xd4, 0xb6, 0x0d, 0xe6, 0x55, 0x04, 0x70, 0xe7, 0x01, 0x72, 0x0c, 0x6d, 0x6b, 0xac, 0x8d, - 0x27, 0xd6, 0x54, 0x1f, 0x19, 0xe6, 0x74, 0xf2, 0xc9, 0xfa, 0x6c, 0xea, 0xc3, 0x77, 0x43, 0xd3, - 0x68, 0xed, 0x90, 0x36, 0x1c, 0xac, 0x82, 0xd6, 0x44, 0xd7, 0x4d, 0xcb, 0x6a, 0x49, 0xf7, 0x81, - 0xf1, 0xf0, 0xa3, 0x39, 0x9a, 0x8c, 0x5b, 0x35, 0x72, 0x08, 0x4f, 0x57, 0x01, 0x93, 0xd2, 0x11, - 0x6d, 0x3d, 0x18, 0x7c, 0xad, 0x41, 0xd3, 0xd0, 0x2e, 0x75, 0x0b, 0xa3, 0x05, 0x77, 0x90, 0x18, - 0xd0, 0x5c, 0x31, 0x07, 0xe9, 0x14, 0xd6, 0xfc, 0xc3, 0x6c, 0xdd, 0xe7, 0x1b, 0x90, 0xfc, 0xb7, - 0xe5, 0x1d, 0x82, 0x70, 0xb4, 0x79, 0xac, 0xe4, 0x65, 0xde, 0xb6, 0xd5, 0x3f, 0xdd, 0xd3, 0xed, - 0x45, 0xd5, 0x36, 0x1f, 0x60, 0x77, 0x6d, 0x34, 0xa4, 0x9b, 0x37, 0x6e, 0x9a, 0x6f, 0xf7, 0x78, - 0x23, 0x56, 0x72, 0x5d, 0x9c, 0x7f, 0x5f, 0xf6, 0xa4, 0x1f, 0xcb, 0x9e, 0xf4, 0x73, 0xd9, 0x93, - 0xbe, 0xfd, 0xea, 0xed, 0x7c, 0x79, 0x3d, 0xe3, 0xc2, 0x4b, 0x6c, 0xc5, 0x09, 0xe6, 0xaa, 0x83, - 0x3e, 0xc6, 0x82, 0xb3, 0x20, 0x9a, 0x55, 0x37, 0x5b, 0x15, 0xb7, 0x21, 0xc6, 0x6a, 0x68, 0x67, - 0xcf, 0x80, 0xdd, 0xc8, 0x2e, 0xfa, 0x9b, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xb4, 0x5b, - 0xe6, 0x1a, 0x04, 0x00, 0x00, + // 518 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x51, 0x6f, 0x12, 0x41, + 0x10, 0xc7, 0x39, 0x40, 0xd4, 0x21, 0x02, 0xdd, 0xa6, 0xe5, 0xa4, 0x4a, 0xc8, 0xd9, 0x46, 0xd2, + 0x44, 0x48, 0xf0, 0xd1, 0x87, 0x86, 0x1e, 0x67, 0x24, 0xb6, 0x62, 0xf6, 0xe0, 0xc5, 0x17, 0xb2, + 0x77, 0x4c, 0x60, 0xc3, 0xd1, 0xa3, 0xb7, 0x0b, 0x91, 0x8f, 0xe0, 0x37, 0xf0, 0x23, 0xf9, 0xe8, + 0x47, 0x30, 0xf8, 0x45, 0xcc, 0xed, 0x1d, 0x94, 0xd6, 0xb3, 0x49, 0x7d, 0xb9, 0xec, 0xce, 0x6f, + 0x67, 0xe6, 0x3f, 0x37, 0x93, 0x81, 0xe2, 0x88, 0x79, 0x6e, 0x33, 0xfc, 0x34, 0xe6, 0x81, 0x2f, + 0x7d, 0x92, 0x0d, 0xcf, 0x95, 0xb2, 0x3f, 0x97, 0x7c, 0xc6, 0xaf, 0x64, 0x73, 0x73, 0x88, 0xb0, + 0xf1, 0x15, 0xa0, 0xd3, 0xa6, 0x28, 0xe6, 0xfe, 0x95, 0x40, 0x72, 0x0c, 0x59, 0xd7, 0x1f, 0xa1, + 0xae, 0xd5, 0xb4, 0x7a, 0xa1, 0x55, 0x6a, 0xa8, 0x38, 0xb6, 0x64, 0x72, 0x21, 0x4c, 0x7f, 0x84, + 0x54, 0x51, 0xa2, 0xc3, 0xe3, 0x19, 0x0a, 0xc1, 0xc6, 0xa8, 0xa7, 0x6b, 0x5a, 0xfd, 0x29, 0xdd, + 0x5c, 0xc9, 0x29, 0xec, 0x8d, 0x98, 0x64, 0x43, 0x8f, 0xad, 0x30, 0x18, 0x4e, 0x90, 0x8f, 0x27, + 0x52, 0xcf, 0xd4, 0xb4, 0x7a, 0x96, 0x16, 0x43, 0x70, 0x11, 0xda, 0x3f, 0x28, 0xb3, 0xf1, 0x0e, + 0x88, 0xbd, 0x70, 0x66, 0x5c, 0x9e, 0x7b, 0xbe, 0x3b, 0xa5, 0x78, 0xbd, 0x40, 0x21, 0xc9, 0x09, + 0x3c, 0x72, 0xc2, 0xbb, 0x92, 0x90, 0x6f, 0x15, 0x1b, 0x5b, 0xbd, 0xd1, 0xb3, 0x88, 0x1a, 0x67, + 0xb0, 0x7f, 0xcb, 0x39, 0xd6, 0x5f, 0x87, 0x5c, 0x80, 0x62, 0xe1, 0xc9, 0xd8, 0x3d, 0xae, 0xe0, + 0xa6, 0x42, 0x1a, 0x73, 0xe3, 0x23, 0xbc, 0x34, 0x27, 0xe8, 0x4e, 0x95, 0x7f, 0x7b, 0xc9, 0xb8, + 0xc7, 0x1c, 0xee, 0x71, 0xb9, 0xda, 0x08, 0x49, 0x2c, 0x45, 0x4b, 0x2e, 0xe5, 0x1a, 0xaa, 0xff, + 0x0a, 0xf6, 0x50, 0x61, 0xe4, 0x04, 0x0a, 0x2a, 0x2f, 0x8b, 0xc2, 0x78, 0xd1, 0x3f, 0x7e, 0x42, + 0x9f, 0x85, 0xd6, 0xf6, 0xc6, 0x68, 0x98, 0x70, 0x40, 0x51, 0x06, 0x1c, 0x97, 0xa8, 0xb2, 0x8a, + 0xff, 0xd1, 0x3d, 0x85, 0xc3, 0xbb, 0x41, 0x1e, 0xac, 0xf7, 0x35, 0xe4, 0x54, 0x4b, 0x84, 0x9e, + 0xae, 0x65, 0x92, 0x3a, 0x16, 0xe3, 0xd3, 0x00, 0xe0, 0x66, 0x92, 0xc8, 0x11, 0x94, 0xed, 0x7e, + 0xbb, 0x3f, 0xb0, 0x87, 0x66, 0xaf, 0x63, 0x0d, 0x07, 0x9f, 0xec, 0xcf, 0x96, 0xd9, 0x7d, 0xdf, + 0xb5, 0x3a, 0xa5, 0x14, 0x29, 0xc3, 0xfe, 0x2e, 0xb4, 0x07, 0xa6, 0x69, 0xd9, 0x76, 0x49, 0xbb, + 0x0b, 0xfa, 0xdd, 0x4b, 0xab, 0x37, 0xe8, 0x97, 0xd2, 0xe4, 0x00, 0xf6, 0x76, 0x81, 0x45, 0x69, + 0x8f, 0x96, 0x32, 0xad, 0x6f, 0x69, 0xc8, 0x77, 0xda, 0x17, 0xa6, 0x8d, 0xc1, 0x92, 0xbb, 0x48, + 0x3a, 0x90, 0xdf, 0x19, 0x1b, 0xa2, 0xc7, 0x03, 0xfe, 0xd7, 0x18, 0x56, 0x9e, 0x27, 0x90, 0xa8, + 0x70, 0x23, 0x45, 0x10, 0x0e, 0x93, 0xdb, 0x4d, 0x5e, 0x45, 0x6e, 0xf7, 0x4e, 0x56, 0xe5, 0xf8, + 0xfe, 0x47, 0xdb, 0x34, 0x97, 0x50, 0xb8, 0xdd, 0x1d, 0x72, 0x14, 0x79, 0x26, 0x36, 0xbe, 0xf2, + 0x22, 0x19, 0x6e, 0xc2, 0x9d, 0x9f, 0xfd, 0x58, 0x57, 0xb5, 0x9f, 0xeb, 0xaa, 0xf6, 0x6b, 0x5d, + 0xd5, 0xbe, 0xff, 0xae, 0xa6, 0xbe, 0xbc, 0x19, 0x73, 0x39, 0x59, 0x38, 0x0d, 0xd7, 0x9f, 0x35, + 0x5d, 0xf4, 0x50, 0x48, 0xce, 0xfc, 0x60, 0xbc, 0x5d, 0x11, 0x4d, 0xb9, 0x9a, 0xa3, 0x68, 0xce, + 0x1d, 0xb5, 0x4f, 0x9c, 0x9c, 0xda, 0x18, 0x6f, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x9a, 0xbe, + 0xc3, 0x8c, 0x63, 0x04, 0x00, 0x00, } diff --git a/types/pb/optimint/optimint.pb.go b/types/pb/optimint/optimint.pb.go index ba5c18fc4..f50bda05a 100644 --- a/types/pb/optimint/optimint.pb.go +++ b/types/pb/optimint/optimint.pb.go @@ -16,12 +16,17 @@ */ package optimint -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import tendermint_abci "github.com/tendermint/tendermint/abci/types" +import ( + fmt "fmt" -import io "io" + proto "github.com/golang/protobuf/proto" + + math "math" + + tendermint_abci "github.com/tendermint/tendermint/abci/types" + + io "io" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -91,7 +96,7 @@ type Header struct { // We keep this in case users choose another signature format where the // pubkey can't be recovered by the signature (e.g. ed25519). ProposerAddress []byte `protobuf:"bytes,11,opt,name=proposer_address,json=proposerAddress,proto3" json:"proposer_address,omitempty"` - // Hash of block aggregator set, at a time of block creation. + // Hash of block aggregator set, at a time of block creation AggregatorsHash []byte `protobuf:"bytes,12,opt,name=aggregators_hash,json=aggregatorsHash,proto3" json:"aggregators_hash,omitempty"` }