mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-07 13:55:17 +00:00
Fixes #828. Adds state sync, as outlined in [ADR-053](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-053-state-sync-prototype.md). See related PRs in Cosmos SDK (https://github.com/cosmos/cosmos-sdk/pull/5803) and Gaia (https://github.com/cosmos/gaia/pull/327). This is split out of the previous PR #4645, and branched off of the ABCI interface in #4704. * Adds a new P2P reactor which exchanges snapshots with peers, and bootstraps an empty local node from remote snapshots when requested. * Adds a new configuration section `[statesync]` that enables state sync and configures the light client. Also enables `statesync:info` logging by default. * Integrates state sync into node startup. Does not support the v2 blockchain reactor, since it needs some reorganization to defer startup.
130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
package statesync
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
amino "github.com/tendermint/go-amino"
|
|
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
const (
|
|
// snapshotMsgSize is the maximum size of a snapshotResponseMessage
|
|
snapshotMsgSize = int(4e6)
|
|
// chunkMsgSize is the maximum size of a chunkResponseMessage
|
|
chunkMsgSize = int(16e6)
|
|
// maxMsgSize is the maximum size of any message
|
|
maxMsgSize = chunkMsgSize
|
|
)
|
|
|
|
var cdc = amino.NewCodec()
|
|
|
|
func init() {
|
|
cdc.RegisterInterface((*Message)(nil), nil)
|
|
cdc.RegisterConcrete(&snapshotsRequestMessage{}, "tendermint/SnapshotsRequestMessage", nil)
|
|
cdc.RegisterConcrete(&snapshotsResponseMessage{}, "tendermint/SnapshotsResponseMessage", nil)
|
|
cdc.RegisterConcrete(&chunkRequestMessage{}, "tendermint/ChunkRequestMessage", nil)
|
|
cdc.RegisterConcrete(&chunkResponseMessage{}, "tendermint/ChunkResponseMessage", nil)
|
|
types.RegisterBlockAmino(cdc)
|
|
}
|
|
|
|
// decodeMsg decodes a message.
|
|
func decodeMsg(bz []byte) (Message, error) {
|
|
if len(bz) > maxMsgSize {
|
|
return nil, fmt.Errorf("msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
|
|
}
|
|
var msg Message
|
|
err := cdc.UnmarshalBinaryBare(bz, &msg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return msg, nil
|
|
}
|
|
|
|
// Message is a message sent and received by the reactor.
|
|
type Message interface {
|
|
ValidateBasic() error
|
|
}
|
|
|
|
// snapshotsRequestMessage requests recent snapshots from a peer.
|
|
type snapshotsRequestMessage struct{}
|
|
|
|
// ValidateBasic implements Message.
|
|
func (m *snapshotsRequestMessage) ValidateBasic() error {
|
|
if m == nil {
|
|
return errors.New("nil message")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SnapshotResponseMessage contains information about a single snapshot.
|
|
type snapshotsResponseMessage struct {
|
|
Height uint64
|
|
Format uint32
|
|
Chunks uint32
|
|
Hash []byte
|
|
Metadata []byte
|
|
}
|
|
|
|
// ValidateBasic implements Message.
|
|
func (m *snapshotsResponseMessage) ValidateBasic() error {
|
|
if m == nil {
|
|
return errors.New("nil message")
|
|
}
|
|
if m.Height == 0 {
|
|
return errors.New("height cannot be 0")
|
|
}
|
|
if len(m.Hash) == 0 {
|
|
return errors.New("snapshot has no hash")
|
|
}
|
|
if m.Chunks == 0 {
|
|
return errors.New("snapshot has no chunks")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// chunkRequestMessage requests a single chunk from a peer.
|
|
type chunkRequestMessage struct {
|
|
Height uint64
|
|
Format uint32
|
|
Index uint32
|
|
}
|
|
|
|
// ValidateBasic implements Message.
|
|
func (m *chunkRequestMessage) ValidateBasic() error {
|
|
if m == nil {
|
|
return errors.New("nil message")
|
|
}
|
|
if m.Height == 0 {
|
|
return errors.New("height cannot be 0")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// chunkResponseMessage contains a single chunk from a peer.
|
|
type chunkResponseMessage struct {
|
|
Height uint64
|
|
Format uint32
|
|
Index uint32
|
|
Chunk []byte
|
|
Missing bool
|
|
}
|
|
|
|
// ValidateBasic implements Message.
|
|
func (m *chunkResponseMessage) ValidateBasic() error {
|
|
if m == nil {
|
|
return errors.New("nil message")
|
|
}
|
|
if m.Height == 0 {
|
|
return errors.New("height cannot be 0")
|
|
}
|
|
if m.Missing && len(m.Chunk) > 0 {
|
|
return errors.New("missing chunk cannot have contents")
|
|
}
|
|
if !m.Missing && m.Chunk == nil {
|
|
return errors.New("chunk cannot be nil")
|
|
}
|
|
return nil
|
|
}
|