Skip to content

Commit

Permalink
Add InitChain ABCI logic (cosmos#159)
Browse files Browse the repository at this point in the history
* Execute InitChain on genesis
* Load height from state
  • Loading branch information
tzdybal authored Oct 22, 2021
1 parent 81760fc commit 39ffb65
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 9 deletions.
46 changes: 46 additions & 0 deletions block/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package block
import (
"context"
"fmt"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/merkle"
"sync/atomic"
"time"

Expand Down Expand Up @@ -75,6 +77,17 @@ func NewManager(
}

exec := state.NewBlockExecutor(proposerAddress, conf.NamespaceID, mempool, proxyApp, logger)
if s.LastBlockHeight+1 == genesis.InitialHeight {
res, err := exec.InitChain(genesis)
if err != nil {
return nil, err
}

updateState(&s, res)
if err := store.UpdateState(s); err != nil {
return nil, err
}
}

agg := &Manager{
proposerKey: proposerKey,
Expand Down Expand Up @@ -284,3 +297,36 @@ func (m *Manager) broadcastBlock(ctx context.Context, block *types.Block) error

return nil
}

func updateState(s *state.State, res *abci.ResponseInitChain) {
// If the app did not return an app hash, we keep the one set from the genesis doc in
// the state. We don't set appHash since we don't want the genesis doc app hash
// recorded in the genesis block. We should probably just remove GenesisDoc.AppHash.
if len(res.AppHash) > 0 {
copy(s.AppHash[:], res.AppHash)
}

if res.ConsensusParams != nil {
params := res.ConsensusParams
if params.Block != nil {
s.ConsensusParams.Block.MaxBytes = params.Block.MaxBytes
s.ConsensusParams.Block.MaxGas = params.Block.MaxGas
}
if params.Evidence != nil {
s.ConsensusParams.Evidence.MaxAgeNumBlocks = params.Evidence.MaxAgeNumBlocks
s.ConsensusParams.Evidence.MaxAgeDuration = params.Evidence.MaxAgeDuration
s.ConsensusParams.Evidence.MaxBytes = params.Evidence.MaxBytes
}
if params.Validator != nil {
// Copy params.Validator.PubkeyTypes, and set result's value to the copy.
// This avoids having to initialize the slice to 0 values, and then write to it again.
s.ConsensusParams.Validator.PubKeyTypes = append([]string{}, params.Validator.PubKeyTypes...)
}
if params.Version != nil {
s.ConsensusParams.Version.AppVersion = params.Version.AppVersion
}
s.Version.Consensus.App = s.ConsensusParams.Version.AppVersion
}
// We update the last results hash with the empty hash, to conform with RFC-6962.
copy(s.LastResultsHash[:], merkle.HashFromByteSlices(nil))
}
2 changes: 2 additions & 0 deletions node/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func TestAggregatorMode(t *testing.T) {
require := require.New(t)

app := &mocks.Application{}
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{})
app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{})
app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{})
Expand Down Expand Up @@ -191,6 +192,7 @@ func createNode(n int, aggregator bool, dalc da.DataAvailabilityLayerClient, key
p2pConfig.Seeds = strings.TrimSuffix(p2pConfig.Seeds, ",")

app := &mocks.Application{}
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{})
app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{})
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{})
Expand Down
2 changes: 2 additions & 0 deletions node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func TestStartup(t *testing.T) {
require := require.New(t)

app := &mocks.Application{}
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
key, _, _ := crypto.GenerateEd25519Key(rand.Reader)
node, err := NewNode(context.Background(), config.NodeConfig{DALayer: "mock"}, key, proxy.NewLocalClientCreator(app), &types.GenesisDoc{ChainID: "test"}, log.TestingLogger())
require.NoError(err)
Expand All @@ -49,6 +50,7 @@ func TestMempoolDirectly(t *testing.T) {
require := require.New(t)

app := &mocks.Application{}
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{})
key, _, _ := crypto.GenerateEd25519Key(rand.Reader)
anotherKey, _, _ := crypto.GenerateEd25519Key(rand.Reader)
Expand Down
7 changes: 4 additions & 3 deletions rpcclient/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"

"github.com/celestiaorg/optimint/config"
"github.com/celestiaorg/optimint/mocks"
Expand Down Expand Up @@ -188,6 +188,7 @@ func getRPC(t *testing.T) (*mocks.Application, *Local) {
t.Helper()
require := require.New(t)
app := &mocks.Application{}
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
key, _, _ := crypto.GenerateEd25519Key(rand.Reader)
node, err := node.NewNode(context.Background(), config.NodeConfig{DALayer: "mock"}, key, proxy.NewLocalClientCreator(app), &types.GenesisDoc{ChainID: "test"}, log.TestingLogger())
require.NoError(err)
Expand All @@ -204,7 +205,7 @@ func TestMempool2Nodes(t *testing.T) {
require := require.New(t)

app := &mocks.Application{}
// app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{})
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
app.On("CheckTx", abci.RequestCheckTx{Tx: []byte("bad")}).Return(abci.ResponseCheckTx{Code: 1})
app.On("CheckTx", abci.RequestCheckTx{Tx: []byte("good")}).Return(abci.ResponseCheckTx{Code: 0})
key1, _, _ := crypto.GenerateEd25519Key(rand.Reader)
Expand Down
29 changes: 29 additions & 0 deletions state/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

abci "github.com/tendermint/tendermint/abci/types"
tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/proxy"
tmtypes "github.com/tendermint/tendermint/types"

Expand Down Expand Up @@ -39,6 +40,34 @@ func NewBlockExecutor(proposerAddress []byte, namespaceID [8]byte, mempool mempo
}
}

func (e *BlockExecutor) InitChain(genesis *tmtypes.GenesisDoc) (*abci.ResponseInitChain, error) {
params := genesis.ConsensusParams
return e.proxyApp.InitChainSync(abci.RequestInitChain{
Time: genesis.GenesisTime,
ChainId: genesis.ChainID,
ConsensusParams: &abci.ConsensusParams{
Block: &abci.BlockParams{
MaxBytes: params.Block.MaxBytes,
MaxGas: params.Block.MaxGas,
},
Evidence: &tmproto.EvidenceParams{
MaxAgeNumBlocks: params.Evidence.MaxAgeNumBlocks,
MaxAgeDuration: params.Evidence.MaxAgeDuration,
MaxBytes: params.Evidence.MaxBytes,
},
Validator: &tmproto.ValidatorParams{
PubKeyTypes: params.Validator.PubKeyTypes,
},
Version: &tmproto.VersionParams{
AppVersion: params.Version.AppVersion,
},
},
Validators: nil,
AppStateBytes: genesis.AppState,
InitialHeight: genesis.InitialHeight,
})
}

// CreateBlock reaps transactions from mempool and builds a block.
func (e *BlockExecutor) CreateBlock(height uint64, commit *types.Commit, state State) *types.Block {
maxBytes := state.ConsensusParams.Block.MaxBytes
Expand Down
2 changes: 1 addition & 1 deletion state/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,4 @@ func TestApplyBlock(t *testing.T) {
require.NoError(err)
require.NotNil(newState)
assert.Equal(int64(2), newState.LastBlockHeight)
}
}
3 changes: 3 additions & 0 deletions store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ func (s *DefaultStore) LoadState() (state.State, error) {
}

err = json.Unmarshal(blob, &state)
s.mtx.Lock()
s.height = uint64(state.LastBlockHeight)
s.mtx.Unlock()
return state, err
}

Expand Down
32 changes: 27 additions & 5 deletions store/store_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package store

import (
"github.com/celestiaorg/optimint/state"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"math/rand"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/celestiaorg/optimint/types"
)

func TestBlockstoreHeight(t *testing.T) {
func TestStoreHeight(t *testing.T) {
t.Parallel()
cases := []struct {
name string
Expand Down Expand Up @@ -51,7 +51,7 @@ func TestBlockstoreHeight(t *testing.T) {
}
}

func TestBlockstoreLoad(t *testing.T) {
func TestStoreLoad(t *testing.T) {
t.Parallel()
cases := []struct {
name string
Expand Down Expand Up @@ -111,6 +111,28 @@ func TestBlockstoreLoad(t *testing.T) {
}
}

func TestRestart(t *testing.T) {
t.Parallel()

assert := assert.New(t)

kv := NewDefaultInMemoryKVStore()
s1 := New(kv)
expectedHeight := uint64(10)
//block := getRandomBlock(expectedHeight, 10)
//err := s1.SaveBlock(block, &types.Commit{Height: block.Header.Height, HeaderHash: block.Header.Hash()})
err := s1.UpdateState(state.State{
LastBlockHeight: int64(expectedHeight),
})
assert.NoError(err)

s2 := New(kv)
_, err = s2.LoadState()
assert.NoError(err)

assert.Equal(expectedHeight, s2.Height())
}

func getRandomBlock(height uint64, nTxs int) *types.Block {
block := &types.Block{
Header: types.Header{
Expand Down

0 comments on commit 39ffb65

Please sign in to comment.