Skip to content

Commit

Permalink
State and block execution (cosmos#58)
Browse files Browse the repository at this point in the history
Resolves cosmos#65.
  • Loading branch information
tzdybal authored Jul 6, 2021
1 parent f436e3f commit 2e8849e
Show file tree
Hide file tree
Showing 30 changed files with 709 additions and 64 deletions.
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package config

// NodeConfig stores Optimint node configuration.
type NodeConfig struct {
P2P P2PConfig
}
1 change: 1 addition & 0 deletions config/defaults.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package config

const (
// DefaultListenAddress is a default listen address for P2P client.
DefaultListenAddress = "/ip4/0.0.0.0/tcp/7676"
)
1 change: 1 addition & 0 deletions config/p2p.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package config

// P2PConfig stores configuration related to peer-to-peer networking.
type P2PConfig struct {
ListenAddress string // Address to listen for incoming connections
Seeds string // Comma separated list of seed nodes to connect to
Expand Down
44 changes: 44 additions & 0 deletions conv/abci/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package abci

import (
"time"

tmproto "github.com/lazyledger/lazyledger-core/proto/tendermint/types"
tmversion "github.com/lazyledger/lazyledger-core/proto/tendermint/version"

"github.com/lazyledger/optimint/hash"
"github.com/lazyledger/optimint/types"
)

// ToABCIHeader converts Optimint header to Header format defined in ABCI.
func ToABCIHeader(header *types.Header) (tmproto.Header, error) {
h, err := hash.Hash(header)
if err != nil {
return tmproto.Header{}, err
}
return tmproto.Header{
Version: tmversion.Consensus{
Block: uint64(header.Version.Block),
App: uint64(header.Version.App),
},
ChainID: "", // TODO(tzdybal)
Height: int64(header.Height),
Time: time.Unix(int64(header.Time), 0),
LastBlockId: tmproto.BlockID{
Hash: h[:],
PartSetHeader: tmproto.PartSetHeader{
Total: 0,
Hash: nil,
},
},
LastCommitHash: header.LastCommitHash[:],
DataHash: header.DataHash[:],
ValidatorsHash: nil,
NextValidatorsHash: nil,
ConsensusHash: header.ConsensusHash[:],
AppHash: header.AppHash[:],
LastResultsHash: header.LastResultsHash[:],
EvidenceHash: nil,
ProposerAddress: header.ProposerAddress,
}, nil
}
5 changes: 4 additions & 1 deletion conv/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/multiformats/go-multiaddr"
)

// TranslateAddresses updates conf by changing Cosmos-style addresses to Multiaddr format.
func TranslateAddresses(conf *config.NodeConfig) error {
if conf.P2P.ListenAddress != "" {
addr, err := GetMultiAddr(conf.P2P.ListenAddress)
Expand All @@ -31,6 +32,8 @@ func TranslateAddresses(conf *config.NodeConfig) error {
return nil
}

// GetMultiAddr converts single Cosmos-style network address into Multiaddr.
// Input format: [protocol://][<NODE_ID>@]<IPv4>:<PORT>
func GetMultiAddr(addr string) (multiaddr.Multiaddr, error) {
var err error
var p2pID multiaddr.Multiaddr
Expand All @@ -50,7 +53,7 @@ func GetMultiAddr(addr string) (multiaddr.Multiaddr, error) {
}
parts = strings.Split(addr, ":")
if len(parts) != 2 {
return nil, ErrInvalidAddress
return nil, errInvalidAddress
}
maddr, err := multiaddr.NewMultiaddr("/ip4/" + parts[0] + "/" + proto + "/" + parts[1])
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions conv/addr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ func TestTranslateAddresses(t *testing.T) {
"invalid listen address",
config.NodeConfig{P2P: config.P2PConfig{ListenAddress: invalidCosmos}},
config.NodeConfig{},
ErrInvalidAddress.Error(),
errInvalidAddress.Error(),
},
{
"invalid seed address",
config.NodeConfig{P2P: config.P2PConfig{Seeds: validCosmos + "," + invalidCosmos}},
config.NodeConfig{},
ErrInvalidAddress.Error(),
errInvalidAddress.Error(),
},
}

Expand Down Expand Up @@ -79,9 +79,9 @@ func TestGetMultiaddr(t *testing.T) {
expected multiaddr.Multiaddr
expectedErr string
}{
{"empty", "", nil, ErrInvalidAddress.Error()},
{"empty", "", nil, errInvalidAddress.Error()},
{"no port", "127.0.0.1:", nil, "failed to parse multiaddr"},
{"ip only", "127.0.0.1", nil, ErrInvalidAddress.Error()},
{"ip only", "127.0.0.1", nil, errInvalidAddress.Error()},
{"with invalid id", "[email protected]:1234", nil, "failed to parse multiaddr"},
{"valid", "127.0.0.1:1234", valid, ""},
{"valid with id", "k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7@127.0.0.1:1234", withID, ""},
Expand Down
11 changes: 7 additions & 4 deletions conv/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import (
"github.com/libp2p/go-libp2p-core/crypto"
)

var ErrNilKey = errors.New("key can't be nil")
var ErrUnsupportedKeyType = errors.New("unsupported key type")
var (
errNilKey = errors.New("key can't be nil")
errUnsupportedKeyType = errors.New("unsupported key type")
)

// GetNodeKey creates libp2p private key from Tendermints NodeKey.
func GetNodeKey(nodeKey *p2p.NodeKey) (crypto.PrivKey, error) {
if nodeKey == nil || nodeKey.PrivKey == nil {
return nil, ErrNilKey
return nil, errNilKey
}
switch nodeKey.PrivKey.Type() {
case "ed25519":
Expand All @@ -23,6 +26,6 @@ func GetNodeKey(nodeKey *p2p.NodeKey) (crypto.PrivKey, error) {
}
return privKey, nil
default:
return nil, ErrUnsupportedKeyType
return nil, errUnsupportedKeyType
}
}
6 changes: 3 additions & 3 deletions conv/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ func TestGetNodeKey(t *testing.T) {
expectedType pb.KeyType
err error
}{
{"nil", nil, pb.KeyType(-1), ErrNilKey},
{"empty", &p2p.NodeKey{}, pb.KeyType(-1), ErrNilKey},
{"invalid", &invalid, pb.KeyType(-1), ErrUnsupportedKeyType},
{"nil", nil, pb.KeyType(-1), errNilKey},
{"empty", &p2p.NodeKey{}, pb.KeyType(-1), errNilKey},
{"invalid", &invalid, pb.KeyType(-1), errUnsupportedKeyType},
{"valid", &valid, pb.KeyType_Ed25519, nil},
}

Expand Down
2 changes: 1 addition & 1 deletion conv/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package conv
import "errors"

var (
ErrInvalidAddress = errors.New("invalid address format, expected [protocol://][<NODE_ID>@]<IPv4>:<PORT>")
errInvalidAddress = errors.New("invalid address format, expected [protocol://][<NODE_ID>@]<IPv4>:<PORT>")
)
7 changes: 6 additions & 1 deletion da/da.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ import (
"github.com/lazyledger/optimint/types"
)

// TODO define an enum of different non-happy-path cases
// StatusCode is a type for DA layer return status.
// TODO: define an enum of different non-happy-path cases
// that might need to be handled by Optimint independent of
// the underlying DA chain.
type StatusCode uint64

// Data Availability return codes.
const (
StatusUnknown StatusCode = iota
StatusSuccess
StatusTimeout
StatusError
)

// ResultSubmitBlock contains information returned from DA layer after block submission.
type ResultSubmitBlock struct {
// Code is to determine if the action succeeded.
Code StatusCode
Expand All @@ -27,6 +30,8 @@ type ResultSubmitBlock struct {
// Hash hash.Hash
}

// DataAvailabilityLayerClient defines generic interface for DA layer block submission.
// It also contains life-cycle methods.
type DataAvailabilityLayerClient interface {
// Init is called once to allow DA client to read configuration and initialize resources.
Init(config []byte, logger log.Logger) error
Expand Down
5 changes: 5 additions & 0 deletions da/lazyledger/lazyledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/lazyledger/optimint/types"
)

// Config holds all configuration required by LazyLedger DA layer client.
type Config struct {
// PayForMessage related params
NamespaceID []byte
Expand All @@ -45,6 +46,8 @@ type Config struct {
RootDir string
}

// LazyLedger implements DataAvailabilityLayerClient interface.
// It use lazyledger-app via gRPC.
type LazyLedger struct {
config Config
logger log.Logger
Expand All @@ -70,11 +73,13 @@ func (ll *LazyLedger) Init(config []byte, logger log.Logger) error {
return err
}

// Start establishes gRPC connection to lazyledger app.
func (ll *LazyLedger) Start() (err error) {
ll.rpcClient, err = grpc.Dial(ll.config.RPCAddress, grpc.WithInsecure())
return
}

// Stop closes gRPC connection.
func (ll *LazyLedger) Stop() error {
return ll.rpcClient.Close()
}
Expand Down
4 changes: 4 additions & 0 deletions da/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"github.com/lazyledger/optimint/types"
)

// MockDataAvailabilityLayerClient is intended only for usage in tests.
// It does actually ensures DA - it stores data in-memory.
type MockDataAvailabilityLayerClient struct {
logger log.Logger

Expand All @@ -18,11 +20,13 @@ func (m *MockDataAvailabilityLayerClient) Init(config []byte, logger log.Logger)
return nil
}

// Start implements DataAvailabilityLayerClient interface.
func (m *MockDataAvailabilityLayerClient) Start() error {
m.logger.Debug("Mock Data Availability Layer Client starting")
return nil
}

// Stop implements DataAvailabilityLayerClient interface.
func (m *MockDataAvailabilityLayerClient) Stop() error {
m.logger.Debug("Mock Data Availability Layer Client stopped")
return nil
Expand Down
1 change: 1 addition & 0 deletions hash/hashing.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/minio/sha256-simd"
)

// Hash creates a SHA-256 hash of object that can be serialized into binary form.
func Hash(object encoding.BinaryMarshaler) ([32]byte, error) {
blob, err := object.MarshalBinary()
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"github.com/lazyledger/optimint/store"
)

// Node represents a client node in Optimint network.
// It connects all the components and orchestrates their work.
type Node struct {
service.BaseService
eventBus *types.EventBus
Expand All @@ -42,6 +44,7 @@ type Node struct {
ctx context.Context
}

// NewNode creates new Optimint node.
func NewNode(ctx context.Context, conf config.NodeConfig, nodeKey crypto.PrivKey, clientCreator proxy.ClientCreator, genesis *types.GenesisDoc, logger log.Logger) (*Node, error) {
proxyApp := proxy.NewAppConns(clientCreator)
proxyApp.SetLogger(logger.With("module", "proxy"))
Expand Down Expand Up @@ -146,6 +149,7 @@ func (n *Node) mempoolPublishLoop(ctx context.Context) {
}
}

// OnStart is a part of Service interface.
func (n *Node) OnStart() error {
n.Logger.Info("starting P2P client")
err := n.P2P.Start(n.ctx)
Expand All @@ -161,26 +165,32 @@ func (n *Node) OnStart() error {
return nil
}

// OnStop is a part of Service interface.
func (n *Node) OnStop() {
n.P2P.Close()
}

// OnReset is a part of Service interface.
func (n *Node) OnReset() error {
panic("OnReset - not implemented!")
}

// SetLogger sets the logger used by node.
func (n *Node) SetLogger(logger log.Logger) {
n.Logger = logger
}

// GetLogger returns logger.
func (n *Node) GetLogger() log.Logger {
return n.Logger
}

// EventBus gives access to Node's event bus.
func (n *Node) EventBus() *types.EventBus {
return n.eventBus
}

// ProxyApp returns ABCI proxy connections to comminicate with aplication.
func (n *Node) ProxyApp() proxy.AppConns {
return n.proxyApp
}
8 changes: 6 additions & 2 deletions p2p/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ const (
txTopicSuffix = "-tx"
)

// TODO(tzdybal): refactor. This is only a stub.
// Tx represents transaction gossiped via P2P network.
type Tx struct {
Data []byte
From peer.ID
}

// TxHandler is a callback function type.
type TxHandler func(*Tx)

// Client is a P2P client, implemented with libp2p.
Expand Down Expand Up @@ -72,7 +74,7 @@ type Client struct {
// TODO(tzdybal): consider passing entire config, not just P2P config, to reduce number of arguments
func NewClient(conf config.P2PConfig, privKey crypto.PrivKey, chainID string, logger log.Logger) (*Client, error) {
if privKey == nil {
return nil, ErrNoPrivKey
return nil, errNoPrivKey
}
if conf.ListenAddress == "" {
conf.ListenAddress = config.DefaultListenAddress
Expand Down Expand Up @@ -141,11 +143,13 @@ func (c *Client) Close() error {
)
}

// GossipTx sends the transaction to the P2P network.
func (c *Client) GossipTx(ctx context.Context, tx []byte) error {
c.logger.Debug("Gossiping TX", "len", len(tx))
return c.txTopic.Publish(ctx, tx)
}

// SetTxHandler sets the callback function, that will be invoked after transaction is received from P2P network.
func (c *Client) SetTxHandler(handler TxHandler) {
c.txHandler = handler
}
Expand Down
2 changes: 1 addition & 1 deletion p2p/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package p2p
import "errors"

var (
ErrNoPrivKey = errors.New("private key not provided")
errNoPrivKey = errors.New("private key not provided")
)
4 changes: 2 additions & 2 deletions proto/optimint.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import "tendermint/abci/types.proto";
// state transition machine.
// This is equivalent to the tmversion.Consensus type in Tendermint.
message Version {
uint32 block = 1;
uint32 app = 2;
uint64 block = 1;
uint64 app = 2;
}

message Header {
Expand Down
4 changes: 2 additions & 2 deletions rpcclient/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

const (
// TODO(tzdybal): make this configurable
SubscribeTimeout = 5 * time.Second
subscribeTimeout = 5 * time.Second
)

var _ rpcclient.Client = &Local{}
Expand Down Expand Up @@ -86,7 +86,7 @@ func (l *Local) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*ctypes.Res
}

// Subscribe to tx being committed in block.
subCtx, cancel := context.WithTimeout(ctx, SubscribeTimeout)
subCtx, cancel := context.WithTimeout(ctx, subscribeTimeout)
defer cancel()
q := types.EventQueryTxFor(tx)
deliverTxSub, err := l.EventBus.Subscribe(subCtx, subscriber, q)
Expand Down
Loading

0 comments on commit 2e8849e

Please sign in to comment.