go mod update for nitro [wip] nitro.Service [wip] run protocgen [wip] nitrobank account
214 lines
5.1 KiB
Go
214 lines
5.1 KiB
Go
package nitro
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"cosmossdk.io/core/server"
|
|
"cosmossdk.io/log"
|
|
serverv2 "cosmossdk.io/server/v2"
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/pflag"
|
|
"github.com/statechannels/go-nitro/node"
|
|
"github.com/statechannels/go-nitro/node/engine"
|
|
"github.com/statechannels/go-nitro/node/engine/chainservice"
|
|
p2pms "github.com/statechannels/go-nitro/node/engine/messageservice/p2p-message-service"
|
|
"github.com/statechannels/go-nitro/node/engine/store"
|
|
"github.com/statechannels/go-nitro/types"
|
|
)
|
|
|
|
// type ServerComponent[T transaction.Tx] interface {
|
|
// Name() string
|
|
// Start(context.Context) error
|
|
// Stop(context.Context) error
|
|
// }
|
|
|
|
const (
|
|
serverName = "nitro"
|
|
)
|
|
|
|
var (
|
|
_ serverv2.HasStartFlags = (*Server)(nil)
|
|
_ serverv2.HasCLICommands = (*Server)(nil)
|
|
_ serverv2.HasConfig = (*Server)(nil)
|
|
// _ serverv2.ConfigWriter = (*Server)(nil)
|
|
)
|
|
|
|
type Server struct {
|
|
*node.Node
|
|
|
|
logger log.Logger
|
|
config *Config
|
|
|
|
// name of Ethereum private key used for chain txs
|
|
EthKey string
|
|
// path to Nitro store directory
|
|
storeDir string
|
|
|
|
ScAddr types.PartyAddress
|
|
}
|
|
|
|
func New(logger log.Logger, cfg server.ConfigMap) (*Server, error) {
|
|
home, _ := cfg[serverv2.FlagHome].(string)
|
|
s := &Server{
|
|
logger: logger.With(log.ModuleKey, serverName),
|
|
storeDir: filepath.Join(home, "nitro")}
|
|
|
|
c := s.Config().(*Config)
|
|
if len(cfg) > 0 {
|
|
if err := serverv2.UnmarshalSubConfig(cfg, s.Name(), &c); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
|
}
|
|
}
|
|
s.config = c
|
|
return s, nil
|
|
}
|
|
|
|
func (s *Server) init(ctx context.Context) error {
|
|
c := s.config
|
|
var clientCtx client.Context
|
|
if v := ctx.Value(client.ClientContextKey); v != nil {
|
|
clientCtx = v.(client.Context)
|
|
}
|
|
|
|
sckey, err := extractPrivKeyBytes(clientCtx.Keyring, c.Pk)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
ethkey, err := extractPrivKeyBytes(clientCtx.Keyring, c.EthPk)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// TODO inject signer or callback into nitro node instead of naked privkey
|
|
// signer.Sign(message)
|
|
// client case is simple signature
|
|
// for validator, multisignatures can be negotiated over abci txs, then loaded into signer
|
|
// Sign(message) only passes once validator's signature is prepared
|
|
|
|
storeOpts := store.StoreOpts{
|
|
PkBytes: sckey,
|
|
UseDurableStore: true,
|
|
DurableStoreFolder: s.storeDir,
|
|
}
|
|
|
|
messageOpts := p2pms.MessageOpts{
|
|
PkBytes: sckey,
|
|
TcpPort: c.MsgPort,
|
|
WsMsgPort: c.WsMsgPort,
|
|
BootPeers: strings.Split(c.BootPeers, ","),
|
|
PublicIp: c.PublicIp,
|
|
ExtMultiAddr: c.ExtMultiAddr,
|
|
}
|
|
chainOpts := chainservice.ChainOpts{
|
|
ChainUrl: c.EthUrl,
|
|
ChainStartBlockNum: c.EthStartBlock,
|
|
ChainAuthToken: c.EthAuthToken,
|
|
ChainPk: hex.EncodeToString(ethkey),
|
|
NaAddress: common.HexToAddress(c.NaAddress),
|
|
VpaAddress: common.HexToAddress(c.VpaAddress),
|
|
CaAddress: common.HexToAddress(c.CaAddress),
|
|
}
|
|
node, store, _, _, err := initNode(s.logger, chainOpts, storeOpts, messageOpts, &engine.PermissivePolicy{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.Node = node
|
|
s.ScAddr = *store.GetAddress()
|
|
return nil
|
|
}
|
|
|
|
func initNode(
|
|
logger log.Logger,
|
|
chainOpts chainservice.ChainOpts,
|
|
storeOpts store.StoreOpts,
|
|
messageOpts p2pms.MessageOpts,
|
|
policymaker engine.PolicyMaker,
|
|
) (
|
|
*node.Node,
|
|
store.Store,
|
|
*p2pms.P2PMessageService,
|
|
chainservice.ChainService,
|
|
error,
|
|
) {
|
|
ourStore, err := store.NewStore(storeOpts)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, err
|
|
}
|
|
|
|
logger.Info("Initializing message service",
|
|
"tcp port", messageOpts.TcpPort,
|
|
"web socket port", messageOpts.WsMsgPort)
|
|
messageOpts.SCAddr = *ourStore.GetAddress()
|
|
messageService := p2pms.NewMessageService(messageOpts)
|
|
|
|
// Compare chainOpts.ChainStartBlock to lastBlockNum seen in store. The larger of the two
|
|
// gets passed as an argument when creating NewEthChainService
|
|
storeBlockNum, err := ourStore.GetLastBlockNumSeen()
|
|
if err != nil {
|
|
return nil, nil, nil, nil, err
|
|
}
|
|
if storeBlockNum > chainOpts.ChainStartBlockNum {
|
|
chainOpts.ChainStartBlockNum = storeBlockNum
|
|
}
|
|
|
|
logger.Info("Initializing chain service...")
|
|
ourChain, err := chainservice.NewL1ChainService(chainOpts)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, err
|
|
}
|
|
|
|
node := node.New(
|
|
messageService,
|
|
ourChain,
|
|
ourStore,
|
|
policymaker,
|
|
)
|
|
|
|
return &node, ourStore, messageService, ourChain, nil
|
|
}
|
|
|
|
func (s *Server) Name() string {
|
|
return serverName
|
|
}
|
|
|
|
func (s *Server) Start(ctx context.Context) error {
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) Stop(context.Context) error {
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) StartCmdFlags() *pflag.FlagSet {
|
|
flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError)
|
|
AddNitroFlags(flags)
|
|
return flags
|
|
}
|
|
|
|
func (s *Server) Config() any {
|
|
if s.config == nil {
|
|
return DefaultConfig()
|
|
}
|
|
return s.config
|
|
}
|
|
|
|
// func (s *Server) WriteConfig(path string) error
|
|
|
|
func (s *Server) CLICommands() serverv2.CLIConfig {
|
|
return serverv2.CLIConfig{
|
|
Commands: []*cobra.Command{
|
|
// command to create payment channel
|
|
s.FundCmd(),
|
|
},
|
|
// Queries: []*cobra.Command{},
|
|
}
|
|
}
|