forked from cerc-io/laconicd
- Add nitro server and x/nitro module
- wire go-nitro p2p through cometbft
- Add distsig server, currently WIP
- integrate DKG and DSS schemes into ABCI methods
- Remove deprecated features
- crisis module
- module invariants
- Update to use newer SDK patterns
- upgrade sdk to v0.53.x
- custom address codec
- expand use of depinject
- migrate e2e tests to system tests
- use depinject to set up integration tests
- change reserved protobuf field name `cerc.registry.v1.Record.type`
- Revise & add documentation
- TransferCoinsToModuleAccount: clarify function
- Update init.sh script
211 lines
5.5 KiB
Go
211 lines
5.5 KiB
Go
package nitro
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"log/slog"
|
|
"path/filepath"
|
|
"sync/atomic"
|
|
|
|
cmtcrypto "github.com/cometbft/cometbft/crypto"
|
|
"github.com/cometbft/cometbft/p2p"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/spf13/pflag"
|
|
nitrocrypto "github.com/statechannels/go-nitro/crypto"
|
|
"github.com/statechannels/go-nitro/node"
|
|
"github.com/statechannels/go-nitro/node/engine"
|
|
"github.com/statechannels/go-nitro/node/engine/chainservice"
|
|
chainutils "github.com/statechannels/go-nitro/node/engine/chainservice/utils"
|
|
"github.com/statechannels/go-nitro/node/engine/store"
|
|
nitrotypes "github.com/statechannels/go-nitro/types"
|
|
|
|
"cosmossdk.io/core/address"
|
|
"cosmossdk.io/log"
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"git.vdb.to/cerc-io/laconicd/server"
|
|
"git.vdb.to/cerc-io/laconicd/utils"
|
|
)
|
|
|
|
const (
|
|
serverName = "nitro"
|
|
|
|
ServerContextKey = "server." + serverName
|
|
)
|
|
|
|
// TODO
|
|
// 1. implement participation as a signing group member:
|
|
// 1.1. initialize group delegate credentials, with distsig over ABCI
|
|
// 1.2. bind custodian contract for chain/adjudicator actions
|
|
// 2. operation to update DKG group members
|
|
// 3. integrate with onboarding module
|
|
|
|
// Server wraps and configures a go-nitro Node.
|
|
type Server struct {
|
|
logger log.Logger
|
|
config *Config
|
|
node *node.Node
|
|
storeDir string // path to Nitro store directory
|
|
reactor *p2pReactor
|
|
keyring keyring.Keyring
|
|
addressCodec address.Codec
|
|
ethAddress nitrotypes.Address
|
|
nodeKey cmtcrypto.PrivKey
|
|
// participantID nitrotypes.Participant
|
|
ready atomic.Bool
|
|
}
|
|
|
|
func New(globalConfig server.ConfigMap, logger log.Logger, kr keyring.Keyring) (*Server, error) {
|
|
home, _ := globalConfig[flags.FlagHome].(string)
|
|
cfg, err := UnmarshalConfig(globalConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := cfg.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
s := &Server{
|
|
config: cfg,
|
|
storeDir: filepath.Join(home, "nitro"),
|
|
reactor: newReactor(cfg, logger.With(log.ModuleKey, serverName, "component", "p2p-reactor")),
|
|
keyring: kr,
|
|
logger: logger.With(log.ModuleKey, serverName),
|
|
addressCodec: utils.NewAddressCodec(),
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func (*Server) Name() string {
|
|
return serverName
|
|
}
|
|
|
|
func (s *Server) Start(ctx context.Context) error {
|
|
if !s.config.Enable {
|
|
s.logger.Info(fmt.Sprintf("%s server is disabled via config", s.Name()))
|
|
return nil
|
|
}
|
|
// TODO: pass keyring through context?
|
|
if err := s.init(s.keyring); err != nil {
|
|
return err
|
|
}
|
|
s.logger.Info("starting Nitro server")
|
|
s.ready.Store(true)
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) Stop(context.Context) error {
|
|
s.logger.Info("stopping Nitro server")
|
|
s.ready.Store(false)
|
|
if s.node != nil {
|
|
return s.node.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) init(kr keyring.Keyring) error {
|
|
var (
|
|
ethkey cmtcrypto.PrivKey
|
|
err error
|
|
c = s.config
|
|
)
|
|
if c.EthKey != "" {
|
|
ethkey, err = utils.ExtractPrivateKeyByUid(kr, c.EthKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return fmt.Errorf("eth-key is not set") // should already be caught by Config.Validate
|
|
}
|
|
s.nodeKey = ethkey
|
|
|
|
storeOpts := store.StoreOpts{
|
|
UseDurableStore: true,
|
|
DurableStoreDir: s.storeDir,
|
|
}
|
|
chainOpts := chainservice.ChainOpts{
|
|
ChainUrl: c.EthURL,
|
|
StartBlockNum: c.EthStartBlock,
|
|
ChainAuthToken: c.EthAuthToken,
|
|
ChainPk: hex.EncodeToString(ethkey.Bytes()),
|
|
}
|
|
// inject SDK logger into slog, which Nitro uses
|
|
loggerImpl, ok := s.logger.Impl().(*slog.Logger)
|
|
if ok {
|
|
slog.SetDefault(loggerImpl)
|
|
} else {
|
|
s.logger.Warn("Logger backend is not slog, cannot set as Nitro logger")
|
|
}
|
|
|
|
store, err := store.NewStore(storeOpts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Compare chainOpts.ChainStartBlock to lastBlockNum seen in store. The larger of the two
|
|
// gets passed as an argument when creating NewEthChainService
|
|
storeBlockNum, err := store.GetLastBlockNumSeen()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chainOpts.StartBlockNum = max(storeBlockNum, chainOpts.StartBlockNum)
|
|
|
|
contractAddresses := node.ContractAddresses{
|
|
NaAddress: common.HexToAddress(c.EthNaAddress),
|
|
VpaAddress: common.HexToAddress(c.EthVpaAddress),
|
|
CaAddress: common.HexToAddress(c.EthCaAddress),
|
|
}
|
|
chainOpts.CreateAdjudicator = chainutils.AdjudicatorCreator(contractAddresses.NaAddress)
|
|
chain, err := chainservice.NewL1ChainService(chainOpts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// note: utils.EthAddressFromPubKey expects uncompressed keys
|
|
ethPubkey, err := crypto.DecompressPubkey(ethkey.PubKey().Bytes())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.ethAddress = nitrotypes.Address(crypto.PubkeyToAddress(*ethPubkey))
|
|
|
|
s.node = node.New(
|
|
newMessageService("laconicd-p2p-"+s.ethAddress.String(), s.reactor),
|
|
chain,
|
|
store,
|
|
&engine.PermissivePolicy{},
|
|
nitrocrypto.NewSimpleCredential(ethkey.Bytes()),
|
|
contractAddresses,
|
|
)
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) Config() any {
|
|
if s.config == nil {
|
|
return DefaultConfig()
|
|
}
|
|
return s.config
|
|
}
|
|
|
|
func (s *Server) StartCmdFlags() *pflag.FlagSet {
|
|
flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError)
|
|
AddFlags(flags)
|
|
return flags
|
|
}
|
|
|
|
func (s *Server) Ready() bool {
|
|
return s.ready.Load()
|
|
}
|
|
|
|
func (s *Server) ContextKey() string {
|
|
return ServerContextKey
|
|
}
|
|
|
|
func (s *Server) P2PReactors() map[string]p2p.Reactor {
|
|
return map[string]p2p.Reactor{"NITRO": s.reactor}
|
|
}
|
|
|
|
func (s *Server) nodeAddress() sdk.AccAddress {
|
|
return sdk.AccAddress(s.nodeKey.PubKey().Address())
|
|
}
|